[HN Gopher] GOTO (2000)
___________________________________________________________________
GOTO (2000)
Author : luu
Score : 32 points
Date : 2024-04-15 07:41 UTC (1 days ago)
(HTM) web link (www.azillionmonkeys.com)
(TXT) w3m dump (www.azillionmonkeys.com)
| whitten wrote:
| Does this mean that compilers have given up on processing GOTO if
| it is written directly by a person, but are fine in analyzing
| code generated in Intermediate code from GOTO-less code ?
| bregma wrote:
| Not at all. The compilers I'm familiar with (and my dayjob is
| maintaining compilers for a commercial OS) all just emit a phi
| node and construct basic blocks for all flow control
| constructs. By the time you're deep in the IR you have no idea
| if it was a do-loop, a for-loop, a while loop, a loop with
| continue and break statements, a series of deeply-nested if-
| statements, and aggregate initializer, or a goto.
|
| The people who religiously avoid the use of gotos are more
| often than not just cargo-culters.
| Findecanor wrote:
| On the contrary. Many passes in a compiler are simpler if the
| control-flow graph is _reducible_ [1], which it is guaranteed
| to be if the program had been written in structured programming
| without any gotos.
|
| It is just that "goto" is closer to assembly code, and
| therefore used in intermediary code representations inside the
| compiler for that reason. But if the compiler had made sure
| beforehand that the control flow is reducible (and don't break
| that in an intermediary pass), then it will remain so.
|
| I find that most uses of gotos in source code are still
| reducible control-flow, but which had just not been expressible
| using structured programming constructs in the language. For
| example jumping out of nested loops, "for-else" and error
| handling. It is very rare that you see "spaghetti code" in
| practice.
|
| 1: https://en.wikipedia.org/wiki/Control-
| flow_graph#Reducibilit...
| justadolphinnn wrote:
| GOTO users are holding society back
| peterhull90 wrote:
| In my youth I had a ZX spectrum which had BASIC with line numbers
| and no renumber command. Sometimes when adding code I'd simply
| run out of line numbers so had to GO TO an unused block of line
| numbers, put the new code there and GO TO just after the original
| code. I've never quite recovered from that.
| bregma wrote:
| My first job out of university was maintaining a FORTRAN IV
| program on a PDP-11. The only control structures in that
| language was IF..GOTO and the arithmetic GOTO. You can still
| write readable half-decent code with that, with discipline. A
| DO loop is still superior for readability.
|
| The horrors of BASIC with its spaghetti of GO TO or its mess of
| PEEKs and POKEs are a justification for permabanning that style
| of programming -- but a decade of typing in listings from
| magazines inspired the generation the brought us the web and
| pocket phones. Maybe it wasn't such a bad thing after all.
| pklausler wrote:
| You had a FORTRAN compiler that didn't have DO loops? I'm
| dubious.
| mmaniac wrote:
| Reminds me of ROM hacking. Overwriting an instruction inside a
| function with a branch to unused memory and jumping back later
| is an easy way to get extra space for the patch you want to
| write.
| sdwr wrote:
| Reminds me of those logic games that operate in (virtual)
| physical space
|
| https://store.steampowered.com/app/300570/Infinifactory/
|
| The feeling being squished into a corner by your own rat's nest
| is really something.
| boomlinde wrote:
| Good "Go To Statement Considered Harmful" considered harmful
| take. I frequently use goto in C to jump to resource cleanup code
| in case of an error. Always turns out more readable than the
| alternatives.
|
| I think I may even have used it in Go once, but I can't remember
| what for. Go's defer keyword obviates the above use of goto, and
| labeled breaks almost any other case I can think of.
| buescher wrote:
| I wouldn't die on that hill but I agree and have done the same.
| In fact I would argue that if you find yourself in arguments
| about the practice it is a good sign your team is at a level
| where you should in fact prohibit all use of goto.
|
| IIRC at least one of the revisions of MISRA specifically allows
| for using goto to break forward to a cleanup-and-return block,
| but others don't.
| JonChesterfield wrote:
| You might find splitting the functions into two works well. The
| outer one tries to allocate whatever resources are needed, the
| inner one assumes they have been allocated. Ends up looking
| something like (copied from one of my C codebases)
| static regex_compare_t
| regex_canonical_equivalent_with_structures(
| regex_cache_t *cache, stringtable_index_t x,
| stringtable_index_t y, intstack_t *stack_arg,
| intmap_t *map_arg) { // fairly complicated code using
| those structures } regex_compare_t
| regex_canonical_equivalent(regex_cache_t *cache,
| stringtable_index_t x,
| stringtable_index_t y) { if (x.value == y.value)
| { return regex_compare_equal; }
| intstack_t stack = intstack_create(256); if
| (!intstack_valid(stack)) { return
| regex_compare_out_of_memory; } intmap_t
| map = intmap_create(16); if (!intmap_valid(map)) {
| intstack_destroy(stack); return
| regex_compare_out_of_memory; }
| regex_compare_t res =
| regex_canonical_equivalent_with_structures(cache, x, y, &stack,
| &map); intstack_destroy(stack);
| intmap_destroy(map); return res; }
| kevindamm wrote:
| I disagree about the examples of when a go-to is useful:
|
| > - Using a single goto and single label to exit several levels
| of scope.
|
| Better handled by putting the nested scope in a function and
| using `return`.
|
| > - Using a goto in the middle of complex construction to short
| cut to the top of a loop.
|
| Use `continue`.
|
| > - Starting a highly optimized do { ... } while loop that is
| best initiated by jumping into the center first. (Because your
| compiler is not cooperating.)
|
| This one's tricky, first be sure that the optimization is
| actually needed. Then, with a quick glance at DRY for apology put
| a copy of the second half of the loop before the `do`.
|
| > - Extensions of duff's device.
|
| Oh come on. The original Duff's device is not intuitive when
| first approaching it, and there is pretty much one use for it. I
| wouldn't even suggest to juniors that they be aware of this trick
| at all, tbh. It's a curiosity but I balk at it being a
| justification for adding gotos to make your own custom extension
| of it. See above, check that you really need such a severe
| optimization. You likely don't.
| OskarS wrote:
| >> - Using a single goto and single label to exit several
| levels of scope.
|
| > Better handled by putting the nested scope in a function and
| using `return`.
|
| I dunno, that seems pretty silly to me. It's a perfectly valid
| use case of goto to jump out of deeply nested loops, and
| refactoring it to break out the inner loop in a function seems
| like pointless busy-work that ultimately makes the code harder
| to read, just so you can avoid a goto.
| clauderoux wrote:
| @OskarS I agree with you... In fact, I have been avoiding
| gotos as a matter of principle for years and now reading the
| different discussions, I think I was misled. This case is
| very, very common. You have 3 intertwined loops and you want
| to get out. The traditional solution is to add some
| intermediate variables to propagate the end of the loops,
| with a cascade "if (toto) break;" which are far from being
| exquisitely elegant... Using a function for that is really
| adding some more complexity and some more stuff on the stack
| for nothing.
| clauderoux wrote:
| Also as a matter of technology, using "if" to get out of
| loops is bad with modern processors and their internal
| predictive algos.
|
| My solution for a long time was to add the test within the
| "for" itself, but it is often confusing for users.
| OskarS wrote:
| Exactly. The only reason not to use goto here is because of
| a dogmatic opposition to ever using goto. In fact, this is
| a rare case where goto makes the flow of the program more
| clear rather than less clear, and alternate solutions are
| just worse.
| bazoom42 wrote:
| > put a copy of the second half of the loop before the `do`
|
| But why is that better than just using a goto? Goto's are
| usually discouraged because they make code hard to follow, but
| if avoiding the goto makes the code even more convoluted, whats
| the point?
| OskarS wrote:
| I've been working my way through the latest volume of The Art of
| Computer Programming (Volume 4B, released last year) which is
| about combinatorial algorithms. One of the very first algorithms
| he presents Algorithm B, "Basic backtrack". It's like a generic
| backtracking algorithm that you could use to solve combinatorial
| problems (e.g. n-queens, things like that).
|
| Every time I've seen this algorithm presented, it's used
| recursion, because that's a very natural way to express
| backtracking. But Knuth doesn't, he basically never uses
| recursion in his TAoCP algorithms, he expresses his algorithms in
| a "flow chart" style, not assuming things like stacks or
| subroutines (in fact, one of the exercises in the chapter is to
| convert Algorithm B to a recursive version, which he then quickly
| dismisses in the answer to the exercise as "elegant, and works
| find for small problems" but fundamentally not very high
| performance and not really clearer than the non-recursive
| version).
|
| So, I set down to implement Algorithm B in a generic way and used
| it to solve n-queens. The way Knuth has written it, it can be
| straightforwardly translated using `goto`s (it has lines like "if
| so-and-so, go to step B4, else B3"), but being the modern,
| structured programmer that I am, i tried to convert it to
| structured programming using loops and if statements.
|
| It was doable, but when benchmarking, my versions were always
| slightly slower than Knuth's original "goto" formulation, and
| honestly I don't think they were more readable either. You had to
| add a bunch of variables to keep some state around that was
| implicit in Knuth's version. The recursive version was definitely
| more readable, but Knuth was of course correct, you pay a
| performance penalty for that readability.
|
| It was a real eye-opener. In the hands of a master, "goto"s
| really do have a place, and when well-deployed, they can
| sometimes simply be superior to "structured" code using loops,
| ifs and recursion.
| afiori wrote:
| One of the arguments un favour if Tail Calls Elimination it
| that it allows to implement a goto-state-machine with mutally
| recursive functions.
| OskarS wrote:
| Yeah, this is a really interesting point, I should try this
| again with [[musttail]] on clang.
| mrkeen wrote:
| I think the 'debate' only makes sense in a sufficiently low-level
| language, at which point you're already taking safety into your
| own hands.
|
| In a higher-level language, it's as silly as asking if you should
| avoid explicit malloc/free when writing SQL.
|
| How would the Rust compiler deal with goto? You could dodge
| ownership and start operating on data before/after it's
| created/deleted.
|
| A try-with-resources/using in Java/C# would no longer offer its
| guarantees.
|
| How about async blocks in general? Do you just wander into
| another thread's code (but keep your own stack frame?)
|
| Lambdas? Closures?
|
| People probably
|
| > regurgitate the age old argument against the use of goto
|
| because there's no new arguments for it.
| neonsunset wrote:
| C# goto does not let you break `using var ...` guarantees or
| violate scopes of other control flow constructs.
| ChrisMarshallNY wrote:
| It is really a post about software dogma.
|
| GOTOs are just one of the oldest ones, but these days, for
| example, we have polymorphism, and OO, in general, and, for some
| folks, anything that is \\(!$HOLY_MANNA) is bad.
|
| In my work, I tend to mix brand-new techniques with very old ones
| (probably older than some of the folks reading these words of
| prose).
|
| _Writing Solid Code_ was written in 1992. Many of its techniques
| have been integrated into toolchains, some are outdated, and some
| are still every bit as valid, today, as they were, then.
|
| I will say that reading it was a watershed, for me.
| JonChesterfield wrote:
| The goto of goto considered harmful is not the goto of C. Somehow
| this subtlety seems to be broadly missed.
|
| The goto of Dijkstra jumps to somewhere else in the program.
| You're somewhere in the call stack and decide to scribble on some
| registers and jump to some arbitrary location. Like longjmp with
| the restrictions taken off. As in across function boundaries.
| When you're writing assembly that works exactly as it it sounds
| like it would.
|
| The goto of C jumps to somewhere else in the same function with a
| bunch of compiler warnings if you manage to bypass an
| initialisation. You can make control flow more complicated within
| a single function, sure.
|
| Goto in C is not a significant problem. Jumping between different
| functions in assembly is however legitimately confusing.
|
| This is something of a pet annoyance because various languages or
| coding standards decide to outlaw the friendly easy goto as it
| has such a scary reputation. This makes some algorithms much more
| complicated to express and others inherently slower.
| nyrikki wrote:
| Note, the common reason people fail to comprehend what Dykstra
| was explaining, is because people don't realize they are almost
| universally adopting one of the three major programming
| paradigms.
|
| While people are familiar with Functional and OOP, most forgot or
| don't know about structured programming. Because it has proven to
| be good by default almost universally.
|
| Look at the COBOL ALTER statement or GCC computed GOTO to see
| what the issues were.
|
| While there are Bohm-Jacopini theorem purists that argue break
| and return, it is the law of diminishing returns.
|
| Break and return may be syntactic sugar for GOTO, but they don't
| have the same problem of the unrestricted transfer of control
| that was and is considered harmful.
___________________________________________________________________
(page generated 2024-04-16 23:01 UTC)