GO TO and reading legacy code
GO TO jumps to a paragraph and does not come back. Before COBOL-85
added inline PERFORM and END-IF, it was the only way to build many
loops and branches, so programs written in the 1970s and 80s are full of it.
You will not write new GO TOs, but you will certainly read them.
A loop built from GO TO
IDENTIFICATION DIVISION.
PROGRAM-ID. GOTODEMO.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-COUNT PIC 9(2) VALUE ZERO.
PROCEDURE DIVISION.
0100-LOOP.
ADD 1 TO WS-COUNT.
DISPLAY "PASS " WS-COUNT.
IF WS-COUNT < 3
GO TO 0100-LOOP.
DISPLAY "DONE".
STOP RUN.
This prints PASS 01, PASS 02, PASS 03, DONE. Note the style: every
statement ends with a full stop, and the IF has no END-IF. The full stop
after GO TO 0100-LOOP is what ends the IF. That is typical of pre-85 code.
Why it is avoided
With PERFORM, every paragraph has one way in and one way out, and you can
read the mainline to see the program's structure. With GO TO, any paragraph
can be entered from anywhere, and to understand one paragraph you must search
the whole program for every jump to it. The result is known as spaghetti
code, and it is the main reason some legacy programs are feared.
There is a subtler danger too: a paragraph that is PERFORMed returns at its
end. If code jumps out of a performed range with GO TO, the pending
return is left behind and control can later return somewhere unexpected.
That kind of bug can take days to find.
The accepted exception
Most shop standards allow exactly one use: GO TO the exit paragraph of a
PERFORM ... THRU range, as you saw earlier. It never leaves the range, so
the structure stays intact.
GO TO DEPENDING ON
Older code uses a computed jump as a switch statement:
0100-DISPATCH.
GO TO 0200-DEPOSIT 0300-WITHDRAWAL 0400-TRANSFER
DEPENDING ON WS-TXN-TYPE.
DISPLAY "UNKNOWN TYPE".
GO TO 0900-END.
A value of 1 jumps to the first name, 2 to the second, and so on. Any other
value falls through to the next statement. Today you would write
EVALUATE WS-TXN-TYPE instead.
ALTER
If you ever see ALTER, it changes the target of a GO TO at run time.
It was removed from the standard. Read the code very carefully and flag
it for your team lead.
Refactoring GO TO code
To untangle a GO TO program:
- Find the loop: a
GO TOthat jumps backwards to an earlier paragraph. That becomes aPERFORM ... UNTIL. The condition that avoided the backward jump becomes theUNTIL. - Find the branches:
IF ... GO TOthat skips forwards over some statements. That becomesIF ... ELSE ... END-IF. - Put the read in its own paragraph and use the priming read shape.
- Run the old and new versions on the same input and compare the output line for line.
On the job
Do not refactor working production code just because it uses GO TO.
Change what the ticket requires and match the existing style. A rewrite
needs its own approval and full regression testing, because a program
that has run nightly for 30 years has behaviours nobody documented.
Your task
The starter is a real-style legacy program: it reads sale amounts until
0 and pays commission at 5% on sales under 1000.00 and 8% on
sales of 1000.00 or more. It works, but it is built entirely from GO TO.
Your team is adopting it into a modern codebase. Rewrite it with no
GO TO, using the structured skeleton (priming read, PERFORM ... UNTIL,
IF ... ELSE ... END-IF). The output must stay exactly the same:
SALE 500.00 COMMISSION 25.00
SALE 1000.00 COMMISSION 80.00
SALE 2499.99 COMMISSION 200.00
TOTAL COMMISSION 305.00
Run the starter first to see what it does. The tests pass for it already; only the no-GO-TO check fails.