I was staring down COBOL code of the following form:
LOOP-COUNTER-INCREMENT. ADD 1 TO J. LOOP-PREDICATE-CHECK. IF J GREATER 10 GO TO MYSTERIOUS-LABEL-1. IF ARRAY-1 (J) NOT = ZERO NEXT SENTENCE ELSE GO TO MYSTERIOUS-LABEL-1. IF ARRAY-2 (J) = MYSTERIOUS-MAGIC-NUMBER-CONSTANT NEXT SENTENCE ELSE GO TO COUNTER-INCREMENT-SPAGGETTIFI. * ...MORE STUFF... GO TO MYSTERIOUS-LABEL-3. COUNTER-INCREMENT-SPAGGETTIFI. GO TO LOOP-COUNTER-INCREMENT. MYSTERIOUS-LABEL-1. EXIT. MYSTERIOUS-LABEL-2. EXIT. MYSTERIOUS-LABEL-3. EXIT.
I had to get some guru help understanding what this was about (thanks Roger!). I didn’t understand why somebody would code a GOTO LABEL, when the the code at that LABEL just did an EXIT. If my intuition could be trusted, I would have assumed that this code was equivalent to the much simpler:
LOOP-COUNTER-INCREMENT. ADD 1 TO J. LOOP-PREDICATE-CHECK. IF J GREATER 10 EXIT. IF ARRAY-1 (J) NOT = ZERO NEXT SENTENCE ELSE EXIT. IF ARRAY-2 (J) = MYSTERIOUS-MAGIC-NUMBER-CONSTANT NEXT SENTENCE ELSE GO TO LOOP-COUNTER-INCREMENT. * ...MORE STUFF... EXIT.
It turns out that intuition is not much use when looking at COBOL code. In this case, that intuition failure is because EXIT doesn’t actually do anything. It is not like a return, which is what I assumed, but is just something that you can put in a paragraph at the end of the section so that the code can exit the section (or at the end of a sequence of paragraphs invoked by PERFORM THRU, so that the code can return to the caller.) The EXIT in such a paragraph is just a comment, and you could use an empty paragraph to do the same thing.
In my transformation of the code the EXIT would do nothing, and execution would just fall through to the next sentence!
Some of the transformations I made are valid. In particular, the spaghettification-indirection used to increment the loop counter, by using a goto to goto the target location instead of straight there, has no reason to exist.
The code in question was an edited version of a program that was generated by a 4GL language (DELTA), so some of the apparent stupidity can be blamed on the code generator. I also assume DELTA can also be blamed for the multiple EXIT paragraphs, when it would seem more natural to just have one per section.
This code also uses EXIT after other paragraph labels too. The first paragraph in the following serving of horror has such an example:
PERFORM TRANSFER-CHECK THRU TRANSFER-CHECK-EXIT. [snip] TRANSFER-CHECK. EXIT. MEANINGLESS-LABEL-1. IF [A COMPOUND PREDICATE CHECK] NEXT SENTENCE ELSE GO TO MEANINGLESS-LABEL-2. [SNIP] PERFORM [MORE STUFF] GO TO MEANINGLESS-LABEL-100. MEANINGLESS-LABEL-2. [STUFF] GO TO MEANINGLESS-LABEL-4. MEANINGLESS-LABEL-3. [increment loop counter, and fall through] MEANINGLESS-LABEL-4. [loop body] ... MEANINGLESS-LABEL-50. GO TO MEANINGLESS-LABEL-3. [SNIP] ... MEANINGLESS-LABEL-99. EXIT. MEANINGLESS-LABEL-100. EXIT. TRANSFER-CHECK-EXIT. EXIT.
Nothing ever branches to MEANINGLESS-LABEL-1 directly, so why even have that there? Using my new found knowledge that EXIT doesn’t do anything, I’m pretty sure that you could just write:
PERFORM TRANSFER-CHECK THRU TRANSFER-CHECK-EXIT. [snip] TRANSFER-CHECK. IF [A COMPOUND PREDICATE CHECK]
Is there some subtle reason that this first no-op paragraph was added? My guess is that the programmer was either being paid per line of code, or the code generator is to blame.
I’m not certain about the flow-control in the TRUE evaluation above. My intuition about the THRU use above is that if we have a GOTO that bypasses one of the paragraphs, then all the preceding paragraphs are counted as taken (i.e. if you get to the final paragraph in the THRU evaluation, no matter how you get there, then you are done.) I’ll have to do an experiment to determine if that’s actually the case.