Live data from Hacker News

Goto (2007)

beej.us

151–160 of 207 posts

Re: Goto (2007)

#151

Structured programming has won so thoroughly and become so pervasive that it's hard nowadays to understand the context in which Dijkstra was writing. 'Don't use goto' doesn't mean 'never ever use a goto under any circumstance', it means 'consider using this thing called a "while" loop instead'.

> 'Don't use goto' doesn't mean 'never ever use a goto under any circumstance',

This is simply not true. When Dijkstra said goto should be considered harmful, he literally meant that programming languages should not suppport it as a feature at all.

Re: Goto (2007)

#152

Probably coming too late to the discussion, but commenting anyway... The issue I think is that people today read "GOTO Considered Harmful" without really understanding the world at the time. Other than simple integer FOR loops, basically all control-flow in the FORTRAN of those days was accomplished with GOTO -- and to numbered lines, not labels. Things we take for granted in all languages today like { code blocks }…

Can you give an example of where you've used goto in C or a C-like language? Or a rough estimate of the number of times you've found goto to be the best solution? I agree with your post in principle, but in practice I can't think of a single example where I've used a goto that wasn't eventually refactored to something better that didn't have the goto. Edit: Probably the most common example (and one given early in the…

Few programmers use goto, because they have been indoctrinated against it and they have no understanding about when goto is bad and when goto is good, but there are many cases where using goto is better (i.e. more clear and/or faster) than what most programmers write now in such occasions.

In some of those cases there are alternatives that could be better than goto, but they cannot be used because they need features that are missing from the programming languages popular now.

One example is state machines. Many programmers when having to implement a state machine use a state variable, e.g. an enumeration and a big "switch" or "case" structure, depending on the language, with a branch for each state.

This kind of implementation follows the method taught now to avoid goto's by adding unnecessary variables that are used to store some state when some condition is detected with the purpose to make a jump later with an extra if or switch instead of doing a jump with a goto immediately when the condition has been detected.

This method of eliminating goto's is pretty stupid, because it not only adds useless variables but it also doubles the number of conditional branches, because each

if (condition) goto label;

is replaced by:

if (condition) variable = value;

...

if (variable == value) {...} or switch (variable) {...}

Besides the accesses to non-cached memory, the conditional branches are the main causes of low performance, so doubling the number of conditional branches can result in much worse performance.

When the second conditional branch is a "switch", that is even worse, because it is typically implemented as an indexed jump, which will be frequently mispredicted.

Instead of using a state variable and a "switch" with branches for states, the right implementation is to have sequences of statements for the states, with the first statement in each sequence labeled with the name of the state.

During each state, when the condition for the transition to another state is detected, a goto is executed, with the name of the next state.

Anyone who believes that this is less clear or more difficult to read than the variant with state variables is delusional, because in the variant with goto's you see immediately the effect of a transition condition, while in the variant with state variables you just see some value being stored and you do not know its purpose until possibly much later when you discover that it is tested for a second conditional branch. Even after you see this use, you are not certain that this is the only place where the variable is used, it might also have other uses and you might need extra time until you are certain about what the program really does.

A more elegant solution for state machines is possible only in languages where tail call optimization is guaranteed.

In such languages each state may be implemented as a separate function and the goto's may be replaced with function invocations in final positions, which are transformed by the compiler into jumps.

While not so many programmers need to write state machines, there are much more frequent uses where goto is superior, e.g. for error management in cases where exceptions are inappropriate, but describing when, why and how would be long.

In general all the problems for which goto was considered harmful are not solved by eliminating goto but by restricting its behavior.

There was a series of research articles by various authors, published between 1970 and 1975, whose conclusion was that the right kind of goto should be allowed to make only forward jumps and that the labels must have a scope restricted to the block in which they are declared. Therefore a goto should be able only to exit from a block but not to enter a block.

An example of a programming language that had this restricted form of goto was the language Mesa, from Xerox.

In C however, it would not be possible to restrict goto only to forward jumps without simultaneously adding guaranteed tail call optimization.

Re: Goto (2007)

#153

Probably coming too late to the discussion, but commenting anyway... The issue I think is that people today read "GOTO Considered Harmful" without really understanding the world at the time. Other than simple integer FOR loops, basically all control-flow in the FORTRAN of those days was accomplished with GOTO -- and to numbered lines, not labels. Things we take for granted in all languages today like { code blocks }…

Can you give an example of where you've used goto in C or a C-like language? Or a rough estimate of the number of times you've found goto to be the best solution? I agree with your post in principle, but in practice I can't think of a single example where I've used a goto that wasn't eventually refactored to something better that didn't have the goto. Edit: Probably the most common example (and one given early in the…

Think of everythin which in java you would put in the catch and finally blocks. Those are nearly always most cleanly handled in C code by doing a goto to the cleanup/return section at the end of the function.

You could work around this via tons of deeply nested blocks, but that makes the code very unreadable. The goto cleanup pattern makes the code intuitive and very readable.

I still have a printout somewhere of an application from the 80s, maybe a dozen pages in small font, every few lines it jumps via goto to somewhere else, depending on state (global variables, of course). It was a serious nightmare to figure out where the code is going. That was the historical context of "goto considered harmful". It sure was! Code like that doesn't exist today, the lessons have been learned. It had nothing to do with clean jump to a cleanup section (which is what a finally{} block is, after all).

Re: Goto (2007)

#154
post #71
post #49

I like the presentation of the three nexted loops. Maybe "break;" should become a shortform for a generalized "break(1);" (= break one level) if we want to avoid using goto. Perhaps this can be implemented by combining a macro with setjmmp() and longjmp() from the standard C library, without requiring a compiler change.

Yep, some goto uses were ostracized without ever providing the alternative. In other languages breaking numerous loops is done by naming the one you want to control: outer: for () { for () { for () { break outer;

Isn't it interesting that all of the examples in the original article can be replaced with a labeled break of arbitrary blocks? Even replacing the continue statement. Solving the problems of goto and keeping the behaviour. Not sure why more languages don't have this

Re: Goto (2007)

#155

Earlier quoted context omitted.

This is where languages that permit nested functions come in handy. You can locally factor out new functions while preserving access to variables in the lexical scope without needing to pass them in as parameters or lift them into a higher level scope (object, class, global, file, etc.).

That's a good solution. The next problem is that many code patterns, such as state machines, if naively converted from `goto` to `call()` will consume a lot of unnecessary stack space. This might not be a problem with a language/compiler that supports tail call optimization.

Perhaps that's true when you're writing performance-critical code.

For most code, readability trumps micro-optimizations.

Re: Goto (2007)

#156
post #14

Earlier quoted context omitted.

People who give blanket rules such as never to use `goto` clearly do not understand where this idea comes from or why it should not be used. Many years ago in my undergrad I submitted a programming assignment in C which used `goto` for cleanup, as is customarily done in the Linux Kernel and other C software and I had points taken off for using `goto`. Heh.

> People who give blanket rules such as never to use `goto` clearly do not understand where this idea comes from or why it should not be used. The idea comes from Dijkstra and he sure as hell did consider it a blanket rule: "I became convinced that the go to statement should be abolished from all 'higher level' programming languages (i.e. everything except, perhaps, machine code)."

C is portable machine code :)

Re: Goto (2007)

#157
post #142

Earlier quoted context omitted.

You are correct, will edit. C is hard, writing C in the browser sans coffee is harder. :-)

I do think this illustrates one of the issues with goto: normally the compiler would be able to warn that you were using buf2 potentially uninitialized, but I think you wouldn't get a warning in this case.

The Clang Static Analyzer could probably find this, if the compiler itself doesn't notice.

Re: Goto (2007)

#158
I learned Basic in the 90s and there was no for, no while, no functions or procedures. Just ifs and goto. Its hard to structure a program just with goto and it's even harder to read it and understand the flow.

Re: Goto (2007)

#159
post #90

Earlier quoted context omitted.

It's not at all like that. `goto` leads to hard to follow, bug-prone code. > Why would an otherwise sane person write code with "rep" and without ever using "jmp"? They wouldn't. Nobody is suggesting that you should avoid `jmp` in assembly. I think maybe you missed the point? The whole "avoid goto" thing is talking about higher level languages than assembly that provide proper flow control primitives like `if`, `for`…

Avoiding jmp in assembly is a sensible thing to do. jmp may stall the pipeline if the branch predictor is wrong. Better to use cmov when you can. And if we're being silly, you only really need mov[1]. [1]: https://github.com/xoreaxeaxeax/movfuscator

That's a completely separate architecture-specific micro-optimisation.

Re: Goto (2007)

#160

Earlier quoted context omitted.

> People who give blanket rules such as never to use `goto` clearly do not understand where this idea comes from or why it should not be used. The idea comes from Dijkstra and he sure as hell did consider it a blanket rule: "I became convinced that the go to statement should be abolished from all 'higher level' programming languages (i.e. everything except, perhaps, machine code)."

C is portable machine code :)

On any modern system it really isn't[0,1].

[0]https://news.ycombinator.com/item?id=16967675

[1]https://queue.acm.org/detail.cfm?id=3212479

Post reply on HN