4 ms·
I don't get why people are so afraid of goto. I looked into Dijkstra's original invective against it and it was an argument for structured programming. People m
by tehjoker 5y ago
I don't get why people are so afraid of goto. I looked into Dijkstra's original invective against it and it was an argument for structured programming. People may not be familiar with that term because it won so thoroughly that only assembly programmers work outside if it. It means constructs like loops, functions, if statements, etc.
In dijkstra's world, people just jumped to any code anywhere in the program, leading to insane spaghetti code that was impossible to read. In C++, goto can no longer jump to anywhere in the program, only within the function. This severely limits the potential damage of goto if the functions are otherwise well constructed.
goto can be used for high performance decision trees, loop exiting, and in C (less so in C++ due to RAII) for freeing memory at the end of a function. I used to fear goto, no longer. However, I would advocate using it only in those situations (possibly others) as in excess it will lead back to the same problems identified by Dijkstra.
- grumpyprole 5y agoYes there's nothing wrong with goto if you need it. Of course, if you are just doing a loop, then a loop structure better communicates the intent and is safer. This is just abstraction and its a good thing. An example from functional programming is direct recursion versus maps/folds, again better to use these abstractions when possible, but direct recursion offers the most flexibility.
- disgruntledphd2 5y ago> People may not be familiar with that term because it won so thoroughly that only assembly programmers work outside if it. I read an old edition of Numerical Recipes, and the first chapter or two was a paean to structured programming, which is when I realised that for, while etc hadn't sprung full-form from the heads of the first compiler developers.
- 10000truths 5y agoThere are several good uses for goto in C. Here's a few I can think of, off the top of my head: 1. Breaking out of nested loops. Sure, you can kludge this with a flag variable, but goto is far more readable. 2. Implementing resource cleanup with stack-style unwinding semantics (i.e. RAII-like). The alternative is usually a bunch of nested if statements, which makes things much harder to read. 3. Implementing state machines. goto is very good at expressing transitions in a graph-like state machine. It doesn't inflate code size as using inline functions would, and it doesn't incur register/stack setup costs that non-inline functions would. However, readability becomes somewhat difficult as the state machine gets more complex, so this is usually relegated to code generators like SMC, re2c, or Ragel. 4. Dispatch loops for threaded virtual bytecode. This is especially niche, and it relies on the labels-as-values gcc extension, but it is very important for implementing performant interpreters. The average C programmer won't necessarily encounter all of these use cases in their career, but that doesn't make any individual one any less important.
- _0w8t 5y agoFor state machines nothing beats tail calls. Those are effectively a goto, but much more expressive and readable. Too bad those are not implemented in supposedly high-performance popular languages.
- MaxBarraclough 5y ago> Too bad those are not implemented in supposedly high-performance popular languages. Perhaps a nitpick: you presumably mean tail-call optimisation, which isn't the same thing as a tail-call. To my knowledge modern C compilers are generally able to perform the optimisation. I believe Java has a hard time with tail-call optimisation as its exception-handling features require it to faithfully track the call stack in case an exception is thrown.
- spc476 5y agoYes, GCC can do tail-call optimization. What you can't do is rely up on in C. Lua has tail-call optimizations and because of that, you can rely upon it. There is a difference.
- MaxBarraclough 5y agoRight, some languages guarantee tail-call optimisation in the language spec itself. The C standard doesn't do this.
- srean 5y ago> Perhaps a nitpick: you presumably mean tail-call optimisation, which isn't the same thing as a tail-call. Tail calls consuming unnecessary stack space is a common pessimisation.
- lmkg 5y agoPart of GP's point is that none of those are "real" gotos. C doesn't have them. C has a construct called "goto" which resembles goto the way that a vacuum cleaner resembles a black hole. A constrained, neutered, much safer shadow of the real thing. If anything, the value of C's goto is evidence in favor of Dijkstra's argument more than against it. Real-world programs don't need real gotos, and the situations where you want them are perfectly well-served by constrained, limited replacements. Like function calls, for-loops, and the thingy that C calls a "goto." For the sake of completeness: there's two main ways in which C's gotos are limited. The first is that they are function-scoped, the second is that they are declared labels rather than arbitrary program points. We nowadays consider that encapsulating data is a good thing. The idea of encapsulated control flow is so taken-for-granted that we don't even realize it could otherwise, but that's effectively what a true goto is.
- opportune 5y agoI agree with you, but I thought about it a bit, and IMO you would probably only ever want to use goto for two or three cases: "repeating" something like going to the beginning of a loop, jumping to error handling, or jumping to a function exit+cleanup (everything else just leads to spaghetti code). I can see a lot of benefits for the first case if you are checking a bunch of conditions and have maybe a doubly nested loop, since its cleaner to e.g. jump back to the outer loop than to do a double break. For the two other conditions you can just return handleErr() or return myCleanup(), which I'd argue is cleaner. Also, I'd argue that you should generally try to avoid doing doubly nested loops with lots of conditionals that you check to determine whether to break or continue. That seems like a code smell.
- tehjoker 5y agoIn most cases I'd agree with you, but in some domains, such as image processing algorithms (particularly for 3d images), those kinds of loops are somewhat common, performance is a first priority, and imo are sometimes more readable with all the conditions in one place even if overall the code is still very difficult. The `return handleErr(val);` is a nicer way to do it in some cases. I'll keep that in mind though you may have to pass a lot of references to the function for it to work.
- gnufx 5y agoI don't remember if it was a rejoinder to Dijkstra, but Knuth wrote "Structured Programming with go to Statements".
- Jtsummers 5y agoPartially a rejoinder, he goes back and forth between structured programming and go to statements considering both sides over the course of the paper. But even in that his conclusion boils down to: go to statements work well if disciplined, but if you have a structured programming construct that actually conveys your intent (by its name, in particular) then that's going to be better in most circumstances.
- buescher 5y agoBefore OO programming was going to fix everything, and agile methodologies were going to solve all our problems, structured programming was the universal cure. Between the remaining religiosity about it and everyone's embarassement about their early coding efforts, goto is just anathema.