

Go To Statement Considered Harmful: A Retrospective - tokenadult
http://david.tribble.com/text/goto.html

======
bullseye
I agree with the sentiment of the article, but the last code example doesn't
help the argument. I think the following are far easier to read/understand
than the goto example that was provided.

    
    
      Token tok;
      while ( (tok = gettoken())!=END )
      {
        if (shift(tok))
          continue;
        if (reduce(tok) && shift(tok))
          continue;
        return ERROR;
      }
      return ACCEPT;
    

\-- if _continue_ is unavailable/taboo --

    
    
      Token tok;
      while ( (tok = gettoken())!=END )
      {
      if ( !shift(tok) && !(reduce(tok) && shift(tok)) )
        return ERROR;
      }
      return ACCEPT;

~~~
abecedarius
I may just be sleep-deprived, but I got

    
    
      Token tok;
      while ((tok = gettoken()) != END)
        while (!shift(tok))
          if (!reduce(tok))
            return ERROR;
      return ACCEPT;

~~~
nkurz
Looks right to me.

But does this strike you as clearer than the original? I like that the
original makes it very clear that we only return ACCEPT if we reach END; that
after a successful shift we continue reading; that after a successful reduce
we shift again; and that we only return ERROR if a reduce fails.

I think yours works the same, but for me at least it takes longer to parse. If
I were actually debugging yours, I might even resort to looking at the
compiled code with objdump and writing the labels in by hand. Presuming it's
correct, I bet this would result in something that looked a lot like the
original!

~~~
abecedarius
Clarity's in the eye of the beholder, yes. I had to scratch my head over the
original to deduce that, ah, for each token before END, there are 0 or more
attempts to reduce, until we can shift (exactly once). To me, that's a clearer
description of what we're trying to do: more declarative. It directly reflects
a grammar: (!END reduce* shift)* END. If we can "parse" that grammar, we get
ACCEPT, else ERROR.

But it's true that different expressions make different things clear.
Structured programming helps most when it gets you to mirror the data's
structure in the code.

------
jrockway
_This terminology reflects the belief at the time that code could be written
which could be formally verified, i.e., that such code could be subjected to a
series of mathematical and logical manipulations that would demonstrate that
the code either contained errors (logic errors, constraint errors, invariant
errors, etc.) or that it did not and thus was thus provably correct. As
mentioned in the Background section above, computer scientists (or at least
programmers) do not think about programming in such terms today._

Citation needed. I know that there is a lot of programming language research
that is going in this direction. It's uncommon in industry, currently, because
it is hard and most programs don't need to be reliable. But, if it were easy
to guarantee correct code, it's something that everyone would want. (I try to
get as close as possible by using functional programming techniques. It
doesn't prevent every error, but it reduces the likelyhood of "something
strange" happening.)

He goes on to mention that line-by-line execution is no longer adequate. I
agree, but I don't think this justifies the use of goto; it shows that we need
functional programming. (Incidentally, functional programs are easier to
verify than programs that make heavy use of goto.)

Anyway, I think he's gone off in the wrong direction. Goto is a very low-level
construct, and it's unnecessary in high-level languages. There, we have much
better control-flow abstractions, such as monads and continuations
(exceptions, looping, continue/break, and function calls are special cases of
continuations ).

~~~
kscaldef
> It's uncommon in industry, currently, because it is hard and most programs
> don't need to be reliable. But, if it were easy to guarantee correct code,
> it's something that everyone would want.

Well, the sort of obvious reason we don't / can't formally validate most
programs is that we don't have a rigorous, complete, consistent description of
what the program is supposed to do.

------
edawerd
The REAL reason why goto statements are harmful:

<http://xkcd.com/292/>

------
aceofspades19
With break and continue, I have never found a reason to actually use goto

~~~
kscaldef
In languages with manual memory management and an impoverished set of control
structures (i.e. C), goto can occasionally be a tolerable tool for error
handling. Once you have automatic memory management or try/catch, there's
pretty much no excuse.

------
TallGuyShort
In my opinion, the only problem in using goto is that it isn't contained.
Loops, functions, if-then-else and switch-case statements all have clear
bounds, but with goto it is very easy to start forming spaghetti code.

There are times I wish I could use a goto in my code, but decide against it
purely because I know it will be criticized by everyone else (or perhaps worse
- used as justification for using goto in some other location)

~~~
edw519
"...with goto it is very easy to start forming spaghetti code."

Exactly! Spaghetti code doesn't spontaneously occur. It happens slowly but
surely, year after year, one quick fix at a time. The odds against it are much
better if the goto cherry is never popped.

"...purely because I know it will be criticized by everyone else..."

And also because you know better ;-)

~~~
scott_s
Except, as Dijkstra pointed out 40 years ago, and the discussion in the
article supports, there are places where gotos are best practice.

------
sfk
Goto is often the cleanest way to jump to error handling at the end of a
function. I always smile at contorted efforts to avoid goto at any cost.
Recently I saw something like this:

    
    
      do {
        /* deeply nested code */ 
        if (error) {
          break;
        }
      } while (0);
    
      /* error handling */
    

And no, it was not the do/while macro trick. It was advertised as structured
programming.

~~~
scott_s
That's the first thing that comes to mind for me when the discussion comes up;
the Linux kernel uses the technique extensively.

To my surprise, Dijkstra actually said the same thing. He called them "alarm
exits."

~~~
fhub
Robert Love ended an opinionated discussion on goto in the linux kernel in
'03. His pseudo code demonstrates a neat error stack unwind technique for c.

<http://kerneltrap.org/node/553/2131> (Scroll to bottom for pseudo code)

------
biohacker42
Written in Notepad, don't shoot me:

enum action { Shift, Read};

action A = Read; Token tok;

while (tok != END)

{

if(A == Read) tok = gettoken();

if(A == shift(tok)) A = read;

else if(A == reduce(tok)) A = shift;

else if(tok == END) return ACCEPT

else return ERROR;

}

\--EDIT--

Awww, no indentation support in HN.

~~~
chaosmachine
I believe you can prefix your lines with two spaces to get <pre> tags.

    
    
      while (1) {
        print "yay";
      }

------
asmosoinio
Interesting: I have worked with Java a lot for the last 6 years or so, and I
just found out about labeled loops from "Example N-1 - Exiting a Nested Loop"
in this article...

