GO TO Loops

Ah, loops. Nowhere are spaghetti-coders more inventive than in the construction of loops. The GO TOs go in and out and all around, in a dizzying variety of complicated combinations.

Nevertheless, a step-by-step incremental approach can untangle even the messiest of loops.

Simple Loops

Let's start out with a simple loop, namely one which satisfies the following requirements:
  1. It consists of a single paragraph.
  2. Only one GO TO returns to the beginning of the loop.
  3. Only one GO TO exits the loop.
  4. The program invokes the loop by PERFORMing THRU an EXIT paragraph (not by a GO TO).
For example:
     PERFORM 3000-LOAD-TABLE THRU 3000-EXIT.
	 ...
 3000-LOAD-TABLE.
*
     PERFORM 3100-GET-TABLE-RECORD.
*
     IF TABLE-EOF
        GO TO 3000-EXIT.
*
     PERFORM 3200-LOAD-TABLE-ENTRY.
     GO TO 3000-LOAD-TABLE.
*
 3000-EXIT.
	 EXIT.
In this example, the exit is conditional; the return to the top of the loop is unconditional. Some cases might be the other way around:
     PERFORM 3300-GET-FIRST-TABLE-RECORD.
*
     IF NOT TABLE-EOF 
        PERFORM 3000-LOAD-TABLE THRU 3000-EXIT.
     ...
 3000-LOAD-TABLE.
*
     PERFORM 3200-LOAD-TABLE-ENTRY.
     PERFORM 3100-GET-NEXT-TABLE-RECORD.
*
     IF NOT TABLE-EOF
        GO TO 3000-LOAD-TABLE.
*
     GO TO 3000-EXIT.
*
 3000-EXIT.
     EXIT.
(That last GO TO probably didn't occur in the original code. We added it in an earlier stage of the rewrite, in order to eliminate some fall-through logic.)

The Standard Canonical GO TO Loop

Whatever your simple GO TO loop may look like, rearrange it to fit the following pattern. (Here and elsewhere I have added arrows to clarify the flow of control. They may not work very well if your browser does not use a fixed-pitch font for the Cobol samples.)
     PERFORM 3000-LOOP THRU 3000-EXIT.
     ...
 3000-LOOP.  <----------------------+
*                                   |
*    do stuff #1.                    |
*                                   |
     IF NOT LOOP-FINISHED           |
*       do stuff #2                 |
        GO TO 3000-LOOP    ---------+ 
     ELSE
*       do stuff #3 
        GO TO 3000-EXIT.   ---------+
*                                   |
 3000-EXIT.   <---------------------+
	 EXIT.
The "do stuff" parts may be trivial. They may be empty -- code CONTINUE statements instead. They may be hideously complex, in which case you should consider pulling them out into separate paragraphs. One way or another, you can always rearrange any simple GO TO loop into the Standard Canonical pattern.

Transforming the Standard Canonical GO TO Loop

Once you have achieved the Standard Canonical pattern, rearrange it into the following PERFORM UNTIL pattern:
     PERFORM 3000-LOOP WITH TEST AFTER
        UNTIL LOOP-FINISHED.
*
*    do stuff #3.
*
     ...
 3000-LOOP.
*
*    do stuff #1.
*
     IF NOT LOOP-FINISHED 
*       do stuff #2.
*
All you did was:
  1. You moved "do stuff #3 out of the loop. Since you execute this fragment only as you exit the loop, put it after the PERFORM UNTIL. (You might have taken this fragment out of the loop in a separate transformation, but here I lump it all together.)
  2. You changed the THRU clause to WITH TEST AFTER and an UNTIL clause.
  3. You deleted both GO TOs.
  4. You added a period to the last "do stuff" line. Of course this addition wouldn't have been necessary if you had used an END-IF.
  5. You deleted the EXIT paragraph (assuming there was no other reference to it).
WITH TEST AFTER ensures that your loop will execute at least once, just as in the original code. If "do stuff #1" is empty, you can omit this clause. You can also omit it if you know that the loop will execute at least once anyway. For example, if you PERFORM something until END-OF-FILE, you know that END-OF-FILE is initially false.

If your dialect of COBOL doesn't support WITH TEST AFTER, you can achieve the same end by other means. Perhaps you can explicitly set or clear some switch just before the PERFORM:

     SET LOOP-NOT-FINISHED TO TRUE.
     PERFORM 3000-LOOP WITH TEST AFTER
        UNTIL LOOP-FINISHED.     
Another trick is to use two PERFORMs, although it looks a little odd:
     PERFORM 3000-LOOP.
     PERFORM 3000-LOOP
        UNTIL LOOP-FINISHED.     
Before you read further, stare at the above example long enough to convince yourself that it works. The new code behaves exactly the same as the old code, but without GO TOs.

Once you get used to the Standard Canonical pattern, you won't have to do this kind of staring. The transformation just becomes another mindless mechanical manipulation.

Ugly Loops

It would be nice if loops were always that simple, but of course they aren't. A loop may span multiple paragraphs. It may have multiple exits and multiple recurrent paths back to the beginning. It may be such a ghastly mess that you can't figure out what it does or how.

Nevertheless, with a systematic, incremental attack, you can still untangle it. At least, you can eliminate the GO TOs. It may still be a ghastly mess, but you'll have a better chance of deciphering it when it is at least formally structured.

The strategy is to apply a series of transformations, step by step, until the complex loop becomes a simple loop. Then you transform it further as described above, and POOF! The GO TOs are gone.


[home]COBOL Home [style forum]COBOL Style Forum [spaghetti]Spaghetti code