3 ms·
Goto gets a bad rap, and I have seen many programs where an explicit goto, to a label that is descriptive, is way clearer (and less brittle under reorganization
by glangdale 9y ago
Goto gets a bad rap, and I have seen many programs where an explicit goto, to a label that is descriptive, is way clearer (and less brittle under reorganization) than a 'structured' break or continue - or some spaghetti of booleans (while (!done) ... ).
It's clearly very easy to write bad code in many ways, but (very) judicious use of goto is occasionally far clearer than assuming goto is always bad and building something complex out of bools, break and continue. It seems to be a test of common sense: if goto is clearer than the alternative, use goto.
- mcguire 9y agoIn one paper on the structured programming issue, Don Knuth has a beautiful axiomatization of goto by Tony Hoare: https://maniagnosis.crsr.net/2011/11/link-o-day-donald-knuth-tony-hoare-and.html https://maniagnosis.crsr.net/2011/11/link-o-day-donald-knuth...
- dbaupp 9y agoYour specific example sounds like the kind of thing addressed by more powerful structure: labelled break, as appears in Java, JS, Rust and Swift (among others, I'm sure). Of course, thinking about labelled break is just dreaming when required/choosing to work in a language without it.
- nickpsecurity 9y agoIt's why some of us built 4GL's, DSL's, preprocessors, and so on that added stuff to such languages but extracted to purely that language. Mine was a BASIC with macros translated to C w/ safety checks.
- userbinator 9y agoUnfortunately, in my experience the abuse of labelled breaks to avoid gotos tends to be even worse than abuse of regular breaks, since the label no longer shows immediately where the flow goes; it only labels the start of the block, when what you really want to see is the end.
- dbaupp 9y agoI guess that could indeed be annoying for reading code, especially if the labelled block/loop is very long (I personally usually end up using these for short nested loops, longer loops usually get broken out into separate functions, and the biggest teams/programs I've worked on haven't been using languages that have this feature). That said, the extra structure/more restrictions of labelled breaks lends itself to compilers and other tooling being more helpful, both for optimisations (although SSA + basic blocks that most compilers now use makes this somewhat irrelevant) and for catching mistakes while, for instance, refactoring. In any case, I strongly disagree that labelled breaks aren't better than regular breaks: the chains of booleans required otherwise are very annoying and error prone.
- sedachv 9y agoLabelled break is strictly less powerful than gotos, and IMO its implementation in Java is far inferior to the block Common Lisp special form (https://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node85.html https://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node85.html) because s-expressions make the lexical scoping unambiguously visible. IMO there is no good substitute for gotos when writing transpilers (and certain interpreters) and low-level concurrency code. The Common Lisp prog macro is the best way that I have seen to use gotos (https://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node91.html https://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node91.html).
- dbaupp 9y agoOf course it is strictly less powerful than gotos. That's actually the point of the more structured constructs: they are more restrictive and so can be reasoned about more easily. Note that I'm specifically piking up on labelled break/continue as a substitute for nested loops like the following while ... { bool shouldBreakOuter = false; while ... { ... shouldBreakOuter = true; break; } if (shouldBreakOuter) break; } since that what the original comments description sounded like. Being a rather general control flow mechanism, there are of course other uses of goto which this doesn't cover. That said, I'm not sure I understand the comparison: the lexical scoping doesn't seem to be ambiguous in Java. Could you expand on what you mean?
- sedachv 9y agoIf you visualize nested scopes as indent levels, the labelXYZ: sits in an indent level above where it is visible. Not only that, but labelXYZ: does not come before the statement that it transfers control to, but two statements before. If all that was not bad enough, most people format the labeled statement to sit at the same indentation level. The combination of these three things is pretty much the worst possible when it comes to reading code. Compare this to block/tagbody/prog and their indentation conventions in Common Lisp.
- mjevans 9y agogoto is best viewed as a low level (unsafe) operation. I wouldn't mind it if the language expressly made me call such a function from a library of other 'unsafe' operations. Optional things that you can include when you really know what you're doing and use them in a limited way. It's one of those tools that is powerful, dangerous, and best avoided when another will suffice. Yet like explosives, sometimes dangerous is the best tool for a job. In the case of a programming language goto can be used to emulate features and/or paradigms that a language doesn't have or doesn't quite do sufficiently. It should ALWAYS have a comment that annotates the intent.
- dingo_bat 9y agoHow is goto an inherently unsafe operation? As long as the usage is clear, it's as safe as any other logical instruction. Problems pop up when nobody else is able to read your code and fix a bug. I feel bad because it has been drilled into my head from the start that goto is unconditionally bad. So I never use it. But I saw a friend replace my spaghetti jungle of break and continue with a simple and clear flow using goto. It was a real mind blowing moment.
- mjevans 9y agoIt's 'unsafe' like how working with raw pointer arithmetic is 'unsafe'. It escapes the paradigms offered to provide regular flow and might also require the compiler to restrict how it handles those sections of code. As others have pointed out elsewhere, it also affects how humans interpret the code, thus it is more likely to be related to bugs as well.
- glangdale 9y agoIt is not remotely unsafe the way that raw pointer arithmetic is unsafe. Proving things about what raw pointer arithmetic winds up doing is undecidable; non-computed goto, on the other hand, is completely obvious. On the theory side, at worst you can create nasty irreducible flow-graphs where you can't simply put code on 'edges', but this is pretty minor. It is very unlikely that a compiler is going to go into the weeds from a local goto; you are spreading FUD. Exceptions, on the other hand, or non-local goto, has a good chance of seriously scrozzling compilers and causing a lot of optimizations to go away. All that being said, the potential to break human understanding of the code with gotos is serious.
- userbinator 9y agoI've been programming for a long time, and have come to the conclusion that "structured programming", then "object-oriented programming", and now "functional programming" --- and whatever comes next --- are all manifestations of dogma: "best practices" that someone obviously thought was a good idea to solve many problems, but not all. The difference between "many" and "all" is where these "best practices" turn into horrible common-sense-violating abominations. I think programming should really be taught starting with Asm, and thus, a language where gotos are the norm. Flowcharting should be considered an essential skill for designing and describing algorithms. Control structures like if/else, do/while, while, for, etc. should be taught as abstractions that are to be used where it would simplify the code (much like all abstractions should be used for), but if your algorithm doesn't fit these structures 100%, it's better to use gotos than to try to "force" it to fit by creating a "spaghetti of booleans". State machines are another use-case where goto makes perfect sense: instead of storing state in additional variables, the current position in the code is enough. It makes debugging much easier when you are actually jumping between the states as you step through the code, rather than looping back up into a switch or a series of if/else checks on another variable.