
The History, Controversy, and Evolution of the Goto Statement [pdf] - dlivingston
http://web.sonoma.edu/users/l/luvisi/goto/goto.pdf
======
svat
This is an excellent article that sets context for, and summarizes, the “goto
debate”.

I know modern programmers who have simply absorbed the received wisdom that
“goto is terrible” and wonder why there even is/was a debate; this short and
concise article should show what goto was used for.

At the time Dijkstra wrote (the letter that the editor titled) "Go To
Statement Considered Harmful", his proposal would have meant programming in a
C-language (of course I know C didn't exist then...) _without_ any `break` or
`continue` in loops, and without `return` except at the end of a function.
There are very few languages today that don't have `break` and `continue`, and
in them (Lua for instance) `goto` is still used.

As the article mentions, it takes much from Knuth's wonderful summarization
paper “Structured Programming with Go To Statements”, and if you find this
interesting you should definitely read it! [https://pic.plover.com/knuth-
GOTO.pdf](https://pic.plover.com/knuth-GOTO.pdf) (Also reprinted in his
book/collection titled _Literate Programming_.)

~~~
int_19h
The funny thing is, it became a cargo cult in many ways. I once worked with a
guy who persistently wrote things like these in C++:

    
    
       do {
          ...
          if (...) break;
          ...
       } while (false);
    

It took me a while to realize what this was about. But, basically, he invented
a way to goto (so long as it was forward) without actually spelling it out.
When I asked him, he gave the usual creed about how "goto is bad", and
wouldn't be convinced that break _is_ goto, especially given how he used it.

Needless to say, this kind of code is actually less readable than if it were
written with a goto in it, because it looks like a loop, but actually isn't
one. With goto, at least it's very clear what it's for, even when there was a
better way to do the same thing.

~~~
superflyguy
I've seen and use that. It's perfectly readable once you understand it's not a
loop. It's handy on c, where you can't try...throw (or don't want to in c++)
where you want to do a few things which you want to treat in a transaction-
like manner. You would return success from the last line in the do loop and
handle errors outside the loop. It's not just about mindlessly avoiding goto;
it's about writing clean structured code.

~~~
BadThink6655321
The problem is trying to understand that it’s not a loop. The first line of
the block says “this is a loop”. The last line of the block says “this isnt’t
a loop.”

The code is, if not outright lying, at least misdirecting.

~~~
superflyguy
You could always add a comment "this is not a loop" if you find it puzzling
that the language allows you to loop zero times.

~~~
BadThink6655321
This is wrong in so many ways. First, I know the language. I’ve been doing
this for almost 50 years. This isn’t a question of what the language allows
but what the coder is trying to do.

Second, experience has taught me that code and comments often don’t agree.
Too, if you have to comment that a loop really isn’t a loop then this is an
indication that something is wrong.

Third, it isn’t a loop: while(false) never loops. That’s the point. Having to
use a forward reference to understand the beginning of something is bad
practice.

Fourth, this construct is almost always a sloppy way to prevent if-else creep.
The code is invariably improved by a) not lying about the loop and b)
refactoring.

------
simonh
My father wrote a BBC Basic interpreter for MS-DOS and lectured at Coventry
University for a while. I remember discussing the Dijksra article with him. He
agreed that goto should generally be avoided, but said he’d used them for very
deep loops where a for loop would have run out of memory. That basic
interpreter was written in assembler, so he was very used to managing program
structure manually with no high level constructs. On early computers, and even
today, sometimes there are constraints other than clarity of the code that
need to be considered. Having said that, I've not used a goto statement for at
least 30 years.

~~~
n17r4m
I kinda understand the feeling your father had. I'm currently tutoring a
friend and while I was reviewing a bit of code from the assignment they had
written, a simple goto would halved a lot of the complexity involved. Instead
I recommended a complicated flag based system that was probably unnecessary.
Although goto is harmful, perhaps it should be taught again as an advanced
technique once more?

~~~
titanix2
> Instead I recommended a complicated flag based system that was probably
> unnecessary.

That's the trigger for me: after more than one flag and the complex states
involved, I may refactor the code using goto because it can actually be a
cleaner solution. Programmers need to be less dogmatic about this case.

~~~
simonh
Sounds like a state machine implementation might work. Hard to say in the
abstract.

------
jsrjenkins
Looking at this from an Assembler point of view, isn't everything really just
a GOTO?

Instruction Register + 1 = GOTO next memory location

If A then B = Branch if equal = GOTO ADDR B

call function = put currebt address in stack and GOTO this address, then GOTO
address on stack.

It seems to me that it is just GOTO all the way down. In fact there really is
nothing else but Memory and GOTO.

Sort of ironic that the very foundations of machine computing is not a very
good idea....

~~~
taejo
"GOTO considered harmful" doesn't mean you should program in assembler without
JMP (and without CALL, for that matter, since the ability to CALL into the
middle of a function is equally problematic).

All flow control is really just GOTO in the same sense that all programming
languages are just assembler. By beginning of the century, most programmers
had realized that this is not the case.

------
jhpriestley
Too many people took the wrong lesson from Dijkstra: that typing out "goto" in
your code was wrong! The point is that structured programming helps you
maintain invariants in your code, and reason from the syntax alone without
having to know the entire dynamic history of the code's execution.

This lesson applies equally well to Angular's "watches" for example, or the
heavily event-driven style seen in some Backbone applications, but these
weren't spelled "goto" so people didn't notice.

------
AndruLuvisi
Original author here. This was a handout for a computer science colloquium
talk that I gave many years ago.

It's fun to see this show up on Hacker News, and thank you all for not holding
it to the same standard as a proper academic paper!

~~~
svat
Thanks for a great article/talk!

Many people misunderstand the _goto_ debate and I'd like to point them to the
great Knuth article for a summary but I can't; it's far too long and contains
a lot of implicit context of its time. Now I have something much better to,
well, ask people to go to.

------
bakul
In John Reynolds "The Discovery of Continuations" paper he cites an
interesting observation by Doug McIlroy:

"So while van Wijngaarden said that goto's were unnecessary ... , Dijkstra
stretched the point to say that goto's were inconvenient. The latter lesson
stuck."

Essentially Van Wijngaarden was talking about a continuation passing style,
where the _remainder_ of a program is represented as a function, so at the end
of a function you always call another function and no function ever returns!
Read the paper: [https://homepages.inf.ed.ac.uk/wadler/papers/papers-we-
love/...](https://homepages.inf.ed.ac.uk/wadler/papers/papers-we-
love/reynolds-discoveries.pdf)

------
bjoli
Funny this should show up, since I am just in the planning stage of
implementing common lisps "tagbody" in scheme. It is mentioned in the article,
but not really explained. It is a neat little localised goto that is explicit.
You can only jump withinthe tagbody.

Why is this useful? Well, goto is a nice little primitive for some things.
Tagbody is used in CL to implement the iter (and maybe loop) macro. Because
sometimes all you want is unconditional jumping around :)

~~~
AndruLuvisi
Original author here. Funny you should mention that. I once made an attempt to
do the same. You can find it at
[http://web.sonoma.edu/users/l/luvisi/scheme/prog.scm](http://web.sonoma.edu/users/l/luvisi/scheme/prog.scm)

One fun thing about this implementation is that labels can be passed to other
functions, or returned from functions, and even used to jump back into
functions that have already exited, since they are based on continuations.

Good luck!

------
notacoward
The statement that jumping to an error handler evolved into modern exceptions
(2.4) is a bit misleading. Exceptions as we know them today have three
properties.

(1) The target is not necessarily known at compile time.

(2) The catcher is likely not the same function as the thrower, with several
other functions in between.

(3) The stack is unwound as part of the throw/catch, including things like
destructors.

Even the uber-powerful "goto" that Dijkstra railed against didn't have these
properties, let alone the tamer "goto" of modern languages like C. Personally
I think (1) and (2) are reasons why exceptions are far worse than gotos, but
if you're going to have them then you'd best have (3) as well. What I always
find strange is people who look down their noses at code with gotos carefully
used for error cleanup, but have no qualms about flinging exceptions around in
their own code. I guess those who do not learn the lessons of history, etc.

~~~
AndruLuvisi
As I recall, my goal was merely to point out that unstructured jumps are still
used for error handling. I was in no way attempting to claim that the two
features are the same.

I'm sorry for any confusion.

~~~
notacoward
No need to apologize. I didn't mean to suggest any failure of intent or
diligence. The problem is only that people who have grown up in a culture of
both "goto is evil" and "exceptions are free" has a poor lens through which to
view the comparison. It's just one of those things that might need to be
clarified in a later version as time marches on around us. In general, I found
the article very well written and helpful.

------
gjm11
An observation just for fun: if you really want to, you can solve the "average
of integers, terminated by 99999" problem _without_ needing any of { goto,
break, duplicated code }. Here's one way:

    
    
      int sum = -99999;
      int count = -1;
      int last = 0;
      do {
        scanf("%d", &last); // scanf is kinda evil but is what article uses
        sum += last;
        count += 1;
      } while (last != 99999);
    

Or you can initialize sum and count to 0 and correct them after the loop
instead of pre-correcting before as the code above does. This results in code
that is a little longer, very marginally slower, and somewhat easier to read.

(There is still a little bit of duplication there: the magic number 99999
appears twice. For this reason I would _actually_ use break, unless required
not to like some of the students in the experiment.)

------
tabtab
I was once in a long online debate about whether "software engineering" was
about machines and math, or the human mind ("wetware"). I leaned the "wetware"
direction. As a "test", I asked the machine/math side to "objectively prove"
that goto's are inferior to blocks (under most circumstances). (To be fair,
the machine/math side was not uniform in their view; I'm oversimplifying for
brevity.)

It was a fascinating debate, but ultimately degenerated into a dispute over
the definition of "go to" and "block", because the boundary is actually quite
fuzzy being that hybrid structures can be created. One would probably have to
settle on specific existing languages first in order to compare.

------
codeulike
GOTO
[https://news.ycombinator.com/item?id=18485598](https://news.ycombinator.com/item?id=18485598)

------
MichaelMoser123
I think old style basic is very easy to learn because of goto, you can do a
lot of stuff just with goto and if statements. I guess this 'goto is harmful'
mantra made it much more difficult to get started with programming as you are
now forced to learn more syntax before it is possible to express anything
meaningful. The lack of goto has created something of an artificial barrier.

~~~
lou1306
> you can do a lot of stuff just with goto and if statements

You can do _all_ stuff with goto and if, but then again, why should you?
Initially it sounds simple, but as the complexity grows it becomes
unmaintainable (especially when goto is unstructured, or non-local, such as
the "On Error GoTo ..." statement). For some time, I had to fix hundred-line
legacy VBA functions and it was _hard_ (i.e. forget trying to do it without a
debbugger).

~~~
MichaelMoser123
I was talking about educational programming: you still have to teach
variables, expressions, assignment, a bunch of library functions, etc. etc.
The job of teaching is not being made easier if you also have to add a lot of
non trivial syntax on top of that.

------
CodeArtisan
GNU C's cleanup attribute and nesting of procedures is better than GOTO in
most of cases.

------
praptak
For a relatively recent problem caused by use of goto:
[https://en.m.wikipedia.org/?title=Goto_fail](https://en.m.wikipedia.org/?title=Goto_fail)

~~~
goto11
The problem is not caused by the use of goto though. It could have been any
other statement and it would still be a bug. The problem is lack of braces or
the misleading indent. If anything this example is a case for Python, not a
case against goto.

~~~
coldtea
> _If anything this example is a case for Python, not a case against goto._

You'd be surprised how many times I've got the indentation wrong in Python.

If a body gets > 20 lines or so, it's easy to miss one statement that ought to
be intended.

~~~
yesenadam
_that ought to be intended._

That ought to be "indented".

~~~
coldtea
Yeah, that mistake was inindented

~~~
yesenadam
Sometimes (like now) I wish I could give a +10 or +100 on HN! Thank you :-)

