1. 20
    1. 22

      It’s worth remembering that the original form of GOTO that Dijkstra objected to was very different from the C one. His article was written at a time when structured programming was only starting to gain traction. The C goto is a purely local construct that affects flow control within a subroutine, whereas older languages used goto in place of explicit subroutines with strict call-return semantics, scoping, and all of the things that are so ingrained in modern programming languages that it’s easy to forget that they’re optional. This made it incredibly hard to understand the control flow of a non-trivial program because it would jump all over the place with ad-hoc policies for how it selected the next code fragment to jump to.

      The C goto eliminates most of these problems because it’s closely tied to the scoping rules of the language. You can’t goto x if x is a label in another function. You can, as the article says, jump over variable initialisation, but you’re implicitly jumping through the allocation of the variable, so the allocation / deallocation of automatic-storage variables is still well defined.

      1. 5

        Here’s a concrete example of old-school Fortran.

           C PROGRAM TO SOLVE THE QUADRATIC EQUATION  
              READ 10,A,B,C  
              DISC = B*B-4*A*C  
              IF (DISC) 15,25,35  
           15 R = 0.0 - 0.5 * B/A  
              AI = 0.5 * SQRTF(0.0-DISC)/A  
              PRINT 11,R,AI  
              GO TO 99  
           25 R = 0.0 - 0.5 * B/A    
              PRINT 21,R    
              GO TO 99  
           35 SD = SQRTF(DISC)  
              R1 = 0.5*(SD-B)/A  
              R2 = 0.5*(0.0-(B+SD))/A  
              PRINT 31,R2,R1  
           99 STOP  
           10 FORMAT( 3F12.5 )  
           11 FORMAT( 19H TWO COMPLEX ROOTS:, F12.5,14H PLUS OR MINUS,  
             * F12.5, 2H I )  
           21 FORMAT( 15H ONE REAL ROOT:, F12.5 )  
           31 FORMAT( 16H TWO REAL ROOTS:, F12.5, 5H AND , F12.5 )  
              END
        
        1. 1

          In case any young’uns are wondering “Where are the variable declarations? Wasn’t FORTRAN statically typed?”

          The answer lies in the old saying… “God is Real. Unless declared Integer.”

          Note the “read 10…” on the 2nd line….

          The input was fixed format, see the line labeled “10”?

          So even if your code was correct…. there were soooo many ways of screwing up running it.

          That “IF (DISC) 15,25,35 “?

          If disc < 0 goto 15, if 0 goto 25, if >0 goto 35

          Brings back old trauma of maintaining this stuff.

          And as I say, old timer scientists mistrusted subroutines (so many ways of screwing up type safety with common blocks and the like)….

          So the average function size was HUUUGE and all variables at global scope…

          What a nightmare!

      2. 2

        Oh the joys of FORTRAN2 computed goto’s and code spaghetti…..

        All written by very smart scientists….. who didn’t have a clue about code quality. Or tests. Or refactoring. Or design. They also often seemed suspicious and distrustful of subroutines.

        Such memories…..

        I feel nauseated.

    2. 10

      It seems that all these cases, possibly except the retry loop, can be handled cleanly with these two language features: as the article notes, labelled loops

      label: for (int i ... ) { continue label; break label; }
      

      and scope guards.

      void *mem = malloc(16);
      scope(exit) free(mem);
      // "free" will be called if we return from here.
      

      These also avoid the unclear interaction of goto with variable declarations.

      (Of course, they aren’t in C. This is why you should use D in -betterC mode :p)