Basic PERFORM and PERFORM THRU
The simplest form, PERFORM PARAGRAPH-NAME, transfers control to a named paragraph or section, executes every statement in it, and then returns control to the statement immediately after the PERFORM once the paragraph falls through to its end. PERFORM FIRST-PARA THRU LAST-PARA executes a contiguous range of paragraphs as a single logical unit, which was the traditional way to group several related paragraphs before in-line PERFORM blocks became common; the range is defined purely by physical source order, so inserting a new paragraph between FIRST-PARA and LAST-PARA silently pulls it into the range. This out-of-line style, where the performed code lives physically separate from the PERFORM statement itself, is a defining characteristic of traditional COBOL structure and differs from the in-line PERFORM available in later standards.
Cricket analogy: PERFORM BOWL-OVER is like a captain calling a specific bowler in for one over and getting control back at the end of it, while PERFORM WARM-UP THRU FIELD-DRILL executes the whole pre-match routine as one contiguous block, the way a T20 side runs its full warm-up sequence before toss.
PROCEDURE DIVISION.
PERFORM INITIALIZE-TOTALS.
PERFORM READ-RECORD THRU PROCESS-RECORD.
PERFORM PRINT-REPORT.
STOP RUN.
INITIALIZE-TOTALS.
MOVE ZERO TO WS-GRAND-TOTAL.
READ-RECORD.
READ CUSTOMER-FILE
AT END SET WS-EOF TO TRUE
END-READ.
PROCESS-RECORD.
ADD WS-AMOUNT TO WS-GRAND-TOTAL.
PRINT-REPORT.
DISPLAY "TOTAL: " WS-GRAND-TOTAL.PERFORM THRU defines its range by physical position in the source, not by any logical grouping marker. If a maintenance programmer inserts a new paragraph between the FIRST and LAST paragraph names, it becomes silently included in the range, and if a paragraph is moved outside those bounds it silently drops out. This fragility is one of the main reasons modern COBOL style favors in-line PERFORM blocks over PERFORM THRU wherever feasible.
PERFORM ... TIMES
PERFORM PARAGRAPH-NAME n TIMES executes the named paragraph exactly n times, where n can be a literal or a numeric data item evaluated once at the start of the loop, making it the direct equivalent of a fixed-count for-loop in other languages. Because the iteration count is fixed at loop entry, changing the value of the counting field inside the loop body has no effect on how many more times the loop will run, which is a common source of confusion for programmers coming from languages where loop bounds are re-evaluated every iteration. PERFORM TIMES has no built-in index variable, so if you need to know which iteration you're on, you must maintain and increment your own counter field inside the loop body.
Cricket analogy: PERFORM BOWL-BALL 6 TIMES mirrors a fixed six-ball over, executing the delivery routine exactly six times regardless of what happens mid-over, unlike PERFORM UNTIL which would stop early on a specific event.
PERFORM ... UNTIL with TEST BEFORE and TEST AFTER
PERFORM ... UNTIL condition repeats the named paragraph or in-line block while the condition is false, stopping as soon as it becomes true, making it COBOL's general-purpose conditional loop equivalent to a while-loop. By default, PERFORM UNTIL uses WITH TEST BEFORE behavior implicitly, checking the condition before each iteration, which means the loop body may execute zero times if the condition is already true on entry. Adding WITH TEST AFTER changes this to a do-while style, evaluating the condition after each execution of the loop body, guaranteeing the body runs at least once, which is the correct choice for patterns like reading the first record before checking for end-of-file.
Cricket analogy: PERFORM BOWL-OVER UNTIL WS-INNINGS-COMPLETE mirrors bowling overs continuously until all ten wickets fall or the over limit is reached, checking the stopping condition before starting each new over.
PROCEDURE DIVISION.
OPEN INPUT CUSTOMER-FILE.
PERFORM READ-NEXT-RECORD
WITH TEST AFTER
UNTIL WS-EOF-FLAG = "Y"
END-PERFORM.
CLOSE CUSTOMER-FILE.
STOP RUN.
READ-NEXT-RECORD.
READ CUSTOMER-FILE
AT END MOVE "Y" TO WS-EOF-FLAG
NOT AT END
ADD 1 TO WS-RECORD-COUNT
END-READ.In-line PERFORM Blocks
An in-line PERFORM places the loop body directly between the PERFORM statement and its END-PERFORM scope terminator, rather than referencing a separately named paragraph, which keeps small loops self-contained and avoids polluting the PROCEDURE DIVISION with single-use paragraph names. In-line PERFORM works with every variation, TIMES, UNTIL, and VARYING, and is generally the preferred modern style because the loop's logic is visible in one place instead of requiring the reader to jump to a separately defined paragraph. The trade-off is that an in-line PERFORM cannot be invoked from elsewhere in the program the way a named paragraph can, so out-of-line PERFORM is still appropriate when the same logic needs to be reused from multiple call sites.
Cricket analogy: An in-line PERFORM is like a commentator describing a bowler's entire run-up and delivery in one continuous shot rather than cutting away to a separate camera feed, keeping the whole action visible in one place.
Modern COBOL style guides generally recommend in-line PERFORM for loop logic used only once, reserving out-of-line PERFORM (with or without THRU) for logic that genuinely needs to be invoked from multiple places in the program. This reduces the number of small, single-use paragraphs cluttering the PROCEDURE DIVISION.
- PERFORM PARAGRAPH-NAME executes a named paragraph out-of-line and returns control after it completes.
- PERFORM ... THRU executes a physically contiguous range of paragraphs as one unit, defined by source order, which can be fragile.
- PERFORM ... TIMES executes a fixed number of iterations determined once at loop entry.
- PERFORM ... UNTIL is COBOL's while-loop; WITH TEST BEFORE (default) may skip the body entirely, WITH TEST AFTER guarantees at least one execution.
- In-line PERFORM embeds the loop body directly with an END-PERFORM terminator instead of referencing a separate paragraph.
- In-line PERFORM is the modern preferred style for single-use loops; out-of-line PERFORM remains useful for reusable logic.
- All PERFORM variations (TIMES, UNTIL, VARYING) can be used either out-of-line or in-line.
Practice what you learned
1. What defines the range of paragraphs executed by PERFORM FIRST-PARA THRU LAST-PARA?
2. In PERFORM PARAGRAPH-NAME n TIMES, what happens if the loop body changes the value of the field used for n?
3. What is the key difference between the default PERFORM UNTIL behavior and WITH TEST AFTER?
4. What is a key limitation of an in-line PERFORM compared to an out-of-line PERFORM of a named paragraph?
Was this page helpful?
You May Also Like
Loops in COBOL
See how COBOL's PERFORM statement is used in practice to build counting loops, nested loops, sentinel-controlled read loops, and how to exit them safely.
Conditional Logic in COBOL
Master COBOL's IF/ELSE, nested conditions, the EVALUATE statement, and condition-names (88-levels) for expressing readable business rules.
MOVE and Arithmetic Statements
Learn how COBOL's MOVE statement reformats data between fields and how ADD, SUBTRACT, MULTIPLY, DIVIDE, and COMPUTE perform arithmetic with proper rounding and overflow handling.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics