GO TO, ALTER and Structured Programming

COBOL COBOL 2014 (ISO/IEC 1989:2014), built with GnuCOBOL 3.x · ✓ verified by execution on 2026-08-16

When maintaining legacy COBOL systems, you will inevitably encounter unstructured “spaghetti code.” Before the widespread adoption of structured programming, control flow was entirely manual. Understanding how legacy code directs execution is essential for safe maintenance and refactoring.

The Unconditional GO TO

The GO TO statement transfers control from one part of the Procedure Division to another. It unconditionally skips or repeats sections of your program.

GO TO PARA-END PARA-END.
cobol ✓ verified output
       IDENTIFICATION DIVISION.
       PROGRAM-ID. GotoBasic.
       PROCEDURE DIVISION.
           DISPLAY "START".
           GO TO PARA-END.
           DISPLAY "SKIPPED".
       PARA-END.
           DISPLAY "END".
           STOP RUN.
Output
START
END

Unlike modern function calls, a GO TO is a one-way trip. Control only returns if another GO TO sends it back. A PERFORM statement, by contrast, transfers control explicitly to one or more procedures and implicitly returns control to the next executable statement.

Predict the output cobol

Read the code. What exactly will it print? Commit to an answer before you look.

       IDENTIFICATION DIVISION.
       PROGRAM-ID. Oneway.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  VAL PIC 9 VALUE 1.
       PROCEDURE DIVISION.
           ADD 1 TO VAL.
           GO TO DO-IT.
           ADD 2 TO VAL.
           DISPLAY VAL.
           STOP RUN.
       DO-IT.
           ADD 3 TO VAL.
           DISPLAY VAL.
Output
5

Dynamic Branching: GO TO DEPENDING ON

Sometimes, legacy code needs to branch dynamically based on a value. The GO TO DEPENDING ON statement transfers control to one of a series of procedures, depending on the value of a data item.

cobol ✓ verified output
       IDENTIFICATION DIVISION.
       PROGRAM-ID. GotoDep.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  CHOICE PIC 9 VALUE 2.
       PROCEDURE DIVISION.
           GO TO OPT-1 OPT-2 OPT-3 DEPENDING ON CHOICE.
       OPT-1.
           DISPLAY "ONE".
           STOP RUN.
       OPT-2.
           DISPLAY "TWO".
           STOP RUN.
       OPT-3.
           DISPLAY "THREE".
           STOP RUN.
Output
TWO

If CHOICE was 1, it would jump to OPT-1. If it was 3, to OPT-3. If it were 4, it would simply fall through and execute OPT-1 anyway. Today, this logic is entirely handled by EVALUATE.

The ALTER Statement: A Maintainer’s Nightmare

If GO TO creates spaghetti code, ALTER turns it into an invisible maze. The ALTER statement changes the transfer point specified in a GO TO statement at runtime. It physically alters the memory address of the target jump instruction.

cobol ✓ verified output
       IDENTIFICATION DIVISION.
       PROGRAM-ID. AlterExample.
       PROCEDURE DIVISION.
           DISPLAY "START".
           ALTER PARA-B TO PROCEED TO PARA-C.
           GO TO PARA-B.
       PARA-B.
           GO TO PARA-D.
       PARA-C.
           DISPLAY "JUMPED TO C".
           STOP RUN.
       PARA-D.
           DISPLAY "JUMPED TO D".
           STOP RUN.
Output
START
JUMPED TO C

Notice that PARA-B explicitly states GO TO PARA-D. But because of the ALTER statement at the top, the program dynamically overwrites that instruction to point to PARA-C. You cannot rely on static analysis to know what the code will do.

The official IBM documentation states: “The ALTER statement encourages the use of unstructured programming practices; the EVALUATE statement provides the same function… but helps to ensure that a program is well-structured.”

Modern Replacements

Whenever possible, legacy GO TO loops should be refactored into structured PERFORM UNTIL blocks, and ALTER logic should be mapped to EVALUATE.

Legacy Loop:

cobol ✓ verified output
       IDENTIFICATION DIVISION.
       PROGRAM-ID. GotoLoop.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  I PIC 9 VALUE 1.
       PROCEDURE DIVISION.
       LOOP-START.
           IF I > 3
               GO TO LOOP-END
           END-IF.
           DISPLAY "I = " I.
           ADD 1 TO I.
           GO TO LOOP-START.
       LOOP-END.
           STOP RUN.
Output
I = 1
I = 2
I = 3

Refactored with PERFORM:

cobol ✓ verified output
       IDENTIFICATION DIVISION.
       PROGRAM-ID. RefactorLoop.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  I PIC 9 VALUE 1.
       PROCEDURE DIVISION.
           PERFORM UNTIL I > 3
               DISPLAY "I = " I
               ADD 1 TO I
           END-PERFORM.
           STOP RUN.
Output
I = 1
I = 2
I = 3

By removing manual GO TO and ALTER references, your code becomes self-documenting and regression-safe.

Check yourself

Why is the ALTER statement considered fundamentally unsafe in COBOL?

Reveal answer

It changes the target of a GO TO at runtime, making static analysis impossible. — ALTER modifies the destination of a GO TO instruction in memory during execution. You cannot know where the GO TO will jump just by reading the code, as it depends on execution history.

How does a PERFORM statement differ from a simple unconditional GO TO?

Reveal answer

PERFORM automatically returns control to the caller, while GO TO is a one-way transfer. — The PERFORM statement explicitly returns control to the next executable statement once finished, making it a structured function call rather than a one-way jump.

What happens when a GO TO DEPENDING ON statement encounters an out-of-bounds integer value?

Reveal answer

Execution falls through to the next sequential statement. — If the value of the target integer is less than 1 or greater than the number of targets provided, the jump does not occur and execution proceeds naturally to the next line.

Challenges

Challenge 1 +50 XP

This program uses an ALTER statement to change behavior. Refactor it to use structured programming (EVALUATE or IF) instead, completely removing the ALTER and GO TO statements. The output must remain exactly the same.

cobol ✓ solution verified at build time

COBOL has no in-browser runtime, so this one is pen-and-paper: work out what the fixed code should be, then open the solution and compare. The expected output below is real — it came from compiling the solution with GnuCOBOL when this page was built.

  • Test 1 — expects "PATH B\n"
Show solution (0 XP)
IDENTIFICATION DIVISION.
PROGRAM-ID. AlterFix.
DATA DIVISION.
WORKING-STORAGE SECTION.
01  CURRENT-PATH PIC X VALUE 'B'.
PROCEDURE DIVISION.
    IF CURRENT-PATH = 'A'
        PERFORM PATH-A
    ELSE
        PERFORM PATH-B
    END-IF.
    STOP RUN.
PATH-A.
    DISPLAY "PATH A".
PATH-B.
    DISPLAY "PATH B".

🐞 Bug Hunt +50 XP

A maintainer accidentally broke this legacy spaghetti code. It should print ONE, then TWO, then stop. Find the bug and fix it.

This code runs. It just does the wrong thing. Read it, find the defect, fix it — the tests below decide when you are right.

cobol ✓ solution verified at build time

COBOL has no in-browser runtime, so this one is pen-and-paper: work out what the fixed code should be, then open the solution and compare. The expected output below is real — it came from compiling the solution with GnuCOBOL when this page was built.

  • Test 1 — expects "ONE\nTWO\n"
Show solution (0 XP)
IDENTIFICATION DIVISION.
PROGRAM-ID. SpaghettiBug.
PROCEDURE DIVISION.
    GO TO STEP-1.
STEP-3.
    STOP RUN.
STEP-1.
    DISPLAY "ONE".
    GO TO STEP-2.
STEP-2.
    DISPLAY "TWO".
    GO TO STEP-3.