Defining PROC modules saves nothing until something PERFORMs them. PERFORM is the call instruction: branch to a labeled module, execute until END-PROC, resume after the call. Batch programmers wrap PERFORM in IF for conditional tax paths; report hooks skip PERFORM entirely because Broadcom calls BEFORE-LINE at the right instant. This tutorial covers unconditional and conditional PERFORM, calls from implied JOB loops, multiple PERFORM targets in one IF/ELSE chain, PERFORM versus CALL to external programs, and mistakes that confuse automatic report invocation with user PERFORM. Calling procedures correctly is the runtime half of modular Easytrieve—the PROC tutorial covers the definition half.
PERFORM proc-name is a single executable statement. Proc-name must match a label with a PROC module in the same activity. No parentheses, no USING clause on PERFORM itself—parameter passing uses shared fields documented in the procedure parameters tutorial. PERFORM does not pass a return value; set output fields before END-PROC returns and read them in the caller.
12345678910111213141516JOB INPUT ORDERS IF ORDER-TYPE EQ 'R' PERFORM RUSH-HANDLING ELSE PERFORM STANDARD-HANDLING END-IF RUSH-HANDLING. PROC SHIP-CODE = 'EXPRESS' FEE = 25.00 END-PROC STANDARD-HANDLING. PROC SHIP-CODE = 'GROUND' FEE = 5.00 END-PROC
Each IF branch may PERFORM a different module—classic strategy pattern without object-oriented syntax. ELSE IF chains can PERFORM three or more modules for status codes. Only one path runs per evaluation unless you structure separate IF blocks. Ensure every branch that must share cleanup either PERFORMs a common FINISH-RTN module or inlines cleanup after END-IF to avoid duplicated END-PROC returns skipping shared logic.
| Pattern | Example | When to use |
|---|---|---|
| Unconditional | PERFORM INIT-COUNTERS in START. PROC caller context | Always-run setup when caller executes |
| IF branch | IF X EQ 1 PERFORM A | Mutually exclusive logic paths |
| Sequential calls | PERFORM A then PERFORM B in JOB | Pipeline steps every record needs |
| Nested in PROC | PERFORM utility inside CALC. PROC | Shared sub-step inside module |
| Guarded call | IF FLAG NE Y PERFORM FIX | Skip module unless error detected |
JOB INPUT reads records repeatedly; PERFORM inside that loop runs once per record when its surrounding IF is true. Counters incremented inside PERFORMed modules accumulate across records unless RESET fields or START. PROC clears them. Distinguish per-record PERFORM from START. PROC PERFORM that should run once—place one-time PERFORM in START or FINISH job PROCs invoked at activity boundaries rather than inside per-record IF that fires every iteration unintentionally.
Report writer events and SCREEN flow invoke special-name PROCs without PERFORM in your job logic. START and FINISH job PROC names run at JOB boundaries when present. SORT BEFORE procs run when named on SORT. Attempting PERFORM on these hooks misunderstands the contract: you define the module; the product schedules it. User PROCs never run until PERFORM or until another PROC PERFORMs them—except when linked from a hook as described in nested procedures.
PERFORM stays inside the compiled Easytrieve program. CALL transfers to an external load module— COBOL subprogram, Assembler routine, C function—with USING parameter lists and optional RETURNS for numeric return codes. Use PERFORM for internal reuse; use CALL when logic lives outside Easytrieve or must share one binary across languages. CALL does not replace PROC; many programs CALL externals from inside a PROC module after preparing fields PERFORM callers already set.
12345678TAX-RTN. PROC WORK-AMT = GROSS-PAY CALL 'TAXCALC' USING WORK-AMT TAX-RATE TAX-OUT RETURNS CALL-STATUS IF CALL-STATUS NE ZERO PERFORM LOG-CALL-ERROR END-IF END-PROC
Define once, call many times. FORMAT-ERR-MSG. PROC may serve validation IF branches, AFTER-SCREEN error handling, and a FINISH cleanup path—each PERFORM re-enters the same END-PROC block. Modules must be reentrant in the sense that they do not assume one-time initialization unless guarded by flags set in START. PROC. Local scratch fields overwritten each entry are fine; global totals incremented each call are intentional accumulators—document which.
Compile errors for undefined procedure usually mean label mismatch, PROC in wrong activity, missing PROC keyword, or prior module missing END-PROC swallowing the label. Check activity scope first when PERFORM looks correct visually. Cross-reference listing sections map PERFORM statements to PROC definitions when your compile listing includes them.
PERFORM overhead is small compared to I/O and sort work in typical batch. Prefer readable modularization over inlining large blocks to save calls. Extremely hot inner loops with one-statement PROCs may justify merge—but profile before optimizing. CALL overhead exceeds PERFORM due to linkage convention and external program entry; batch designs batch external calls when possible rather than CALL per field change.
PERFORM is yelling a recipe name to the kitchen. The cooks open that recipe card, follow it, say done, and wait for your next instruction. You decide when to yell which recipe—only for spicy food, or for every plate. Some recipe names are ones only the head chef calls automatically at dessert time; you do not yell those yourself.
1. User PROC modules are invoked with:
2. PERFORM inside IF runs when:
3. BEFORE-LINE. PROC is called by:
4. After END-PROC, execution continues:
5. CALL differs from PERFORM because: