3 ms·
gotos can be used without shame. Dijkstra was wrong (in this rare case). defer is cleaner, though.
by foooorsyth 2y ago
gotos can be used without shame. Dijkstra was wrong (in this rare case).
defer is cleaner, though.
- jerf 2y agoDijkstra was not wrong. Modern programmers are wrong in thinking that the goto that they use is what Dijkstra was talking about, merely because of the fact it happens to be called the same thing. I mean, I get how that can happen, no sarcasm, but the goto Dijkstra was talking about and what is in a modern language is not the same. https://jerf.org/iri/post/2024/goto/ https://jerf.org/iri/post/2024/goto/ The goto Dijkstra is talking about is dead. It lives only in assembler. Even BASIC doesn't have it anymore in any modern variant. Modern programmers do not need to live in fear of modern goto because of how awful it was literally 50 years ago.
- Spivak 2y agoOr the tl;dr in modern parlance Dijkstra was railing against the evils of setjmp.
- ryao 2y agoLua uses it for error handling. It is really hard to understand the lua code. :/
- zzo38computer 2y agoSometimes setjmp is useful and I had occasionally used it, but usually it is not needed. There is certain considerations you must make in order to be careful when you are using setjmp though. (Free Hero Mesh uses setjmp in the execute_turn function. This function will call several other functions some of which are recursive, and sometimes an error occurs or WinLevel or LoseLevel occurs (even though these aren't errors), in which case it will have to return immediately. I did try to ensure that this use will not result in memory leaks or other problems; e.g. v_set_popup allocates a string and will not call longjmp while the string is allocated, until it has been assigned to a global variable (in which case the cleanup functions will handle this). Furthermore, the error messages are always static, so it is not necessary to handle the memory management of that either.)
- kbolino 2y agoNo, even setjmp/longjmp are not as powerful or dangerous. The issue is not the locality of the jump, but the lack of any meaningful code structure enforced by the language. Using setjmp and longjmp properly still saves and restores context. You still have a function call stack, a convention for saving and restoring registers, locally scoped variables, etc. Though, using setjmp/longjmp improperly on some platforms might come close, since you're well into undefined behavior territory. Parent is correct that this doesn't really exist outside of assembly language anymore. There is no modern analogue, because Dijkstra's critique was so successful.
- readthenotes1 2y ago"when I see modern code that uses goto, I actually find that to be a marker that it was probably written by highly skilled programmers. " He should have said "correct code", not "modern code" because the times I remember seeing goto the code was horribly incorrect and unclear. (With break and continue, someone has to be doing something extra funky to need goto. And even those were trigger signs to me, as often they were added as Hail Mary's to try to make something work) {I typically reviewed for clarity, correctness, and consistency. In that order}
- huhtenberg 2y agoThe interpretation of Dijkstra's sentiment in your blog post is plain wrong. His paper [1] clearly talks about goto semantics that are still present in modern languages and not just unrestricted jmp instructions (that may take you from one function into the middle of another or some such). I'd urge everyone to give it a skim, it's very short and on point. [1] https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.p...
- jerf 2y agoWell, there you get that I don't believe in letting certain people own ideas and then stick to them as if they were given revelation from on high about how things should work. The distinctive thing about goto that breaks structured programming, to the point that functions as we think of them today can't even exist in such an environment, is the ability to jump arbitrarily. I'm way less worried about uses of goto that are rigidly confined within some structured programming scope. As long as they stay confined to specific functions, they are literally orders of magnitude less consequential than the arbitrary goto, and being an engineer rather than an academic, I take note of such things. I don't ask Alan Kay about the exact right way to do OO, I don't ask Fielding about the exact right way to do REST interfaces, and I don't necessarily sit here and worry about every last detail of what Dijkstra felt about structured programming. He may be smarter than me, but I've written a lot more code in structured paradigms than he ever did. (This is not a special claim to me; you almost certainly have too. You should not ignore your own experiences.)
- jcranmer 2y agoYour analysis is wrong. Dijkstra was a big proponent of structured programming, and the fundamental thesis of his argument is that the regular control flow structures we're used to--if statements, loops, etc.--all represent a tree-based data structure. In essence, the core argument is that structured programming allows you to mentally replace large blocks of code with black boxes whose exact meanings may not be important. The problem with GOTO, to Dijkstra, is that it violates that principle. A block can arbitrarily go somewhere else--in the same function, in a different function (which doesn't exist so much anymore)--and that makes it hard to reason about. Banning GOTO means you get the fully structured program that he needs. (It's also worth remembering here that Dijkstra was writing in an era where describing algorithms via flowcharts was common place, and the use of if statements or loops was far from universal. In essence, this makes a lot of analysis of his letter difficult, because modern programmers just aren't exposed to the kind of code that Dijkstra was complaining about.) Since that letter, modern programming has embraced the basic structured programming model--we think of code almost exclusively of if statements and loops. And, in many language, goto exists only in extremely restricted forms (break, continue, and return as anything other than the last statement of a function). It should be noted that Dijkstra's argument actually carries through to railing against the modern versions of break et al, but the general program of structured programming has accepted that "early return" is an acceptable deviation from the strictly-single-entry-single-exit that is desired that doesn't produce undue cognitive overhead. Even where mind-numbing goto exists today (e.g., C), it's similarly largely used in ways that are similar to "early return"-like concepts, not the flowchart-transcribed-to-code-with-goto-as-sole-control-flow style that Dijkstra is talking about. And, personally, when I work with assembly or LLVM IR (which is really just portable assembly), I find that the number one thing I want to look at a very large listing is just something that converts all the conditional/unconditional jumps into if statements and loops. That's really the main useful thing I want from a decompiler; everything else as often as not just turns out to be more annoying to work with than the original assembly.
- jerf 2y agoI struggle with how you claim my "analysis is wrong", and then basically reiterate my entire point. I know it's not that badly written; other people got it just fine and complain about what it actually does say. The modern goto is not the one he wrote about. It is tamed and fits into the structured programming paradigm. Thus, ranting about goto as if it is still the 1960s is a pointless waste of time. Moreover, even if it does let you occasionally violate structured programming in the highly restricted function... so what? Wrecking one function is no big deal, and generally used when it is desirable that a given function not be structured programming. Structured programming, as nice as it is, is not the only useful paradigm. In particular state machines and goto go together very nicely, where the "state machine" provides the binding paradigm for the function rather than structured programming. It is perhaps arguably the distinctive use case that it lives on for in modern languages.