Contrary to popular reputation, there are a handful of use cases where "goto" makes the code simpler, cleaner, more readable, and (in rarer cases) faster. In these cases, you should use goto statements. A good programmer can recognize these cases and use goto appropriately. Goto is never necessary in a strict sense but occasionally it can eliminate some pretty ugly spaghetti code.
The use cases for goto I see are primarily complex/thorough error handling (e.g. unwinding some concurrency control mechanisms) and certain low-level state machine patterns. I would expect to see these kinds of use cases in the Linux kernel.
In practice you will do the same thing as unwinding the stack. You'll jump to the end of a function where you'll likely free some heap buffers on your way out and you'll return error status to the caller. What will likely happen next is the caller will bubble up the error: free buffers and report error status to their caller. It works out to pretty much the same thing as a modern C++ code base using RAII, just more manual.
Seems like they use it for most of the error handling, that's true. Almost as many of these as there are switch statements (and 1/3 of if statements). It would be cool if someone could analyze keywords from different projects. Maybe one could give that as use cases in universites instead, that would seem to be alot more practical.
EDIT: Upon closer inspection it seems like even if 'gotos' make everything nastier the extra added performance is worth it.
As long as they're local I guess, like a handmade `finally` clause. It's like mutation in functional programming languages, they're allowed as long as they don't leak. IIRC Zed Shaw's Learn C the Hard Way has some nice `goto` examples..
Breaking from nested loops with goto is also cleaner and simpler. Which is actually one of the reasons some higher level languages even have a goto statement.
For that use-case in particular, a "labeled break" is an alternative that some languages use (like java). I somewhat semantically prefer it if given the choice (name the loop being broken, vs. naming the end-point to jump to), though that preference isn't strong.
The original context of the "GOTO considered harmful" is lost on most of us, as at the time there were large swaths of developers that were trained before structured programming took off, so people were using global variables and GOTOs instead of procedures and functions. GOTO has its place, specially in C.
It is sinful to jump into a different function and pass around information as global state. GOTO as functionality is tangential in this matter.
Growing up in the 80s, that's how a lot of books taught us BASIC, because they catered to a lowest-common-denominator implementation. Fortunately, I was using BBC BASIC, with functions, procedures and REPEAT-UNTIL (and later WHILE and CASE), and the BBC-specific books taught structured programming.
You skipped the "and pass information around as global state" part. It obviously depends on your language, but ideally an Exception object should be a specific class you can choose to catch or re-raise, and it should include a message. None of the calling state should be visible to you.
I give you that I skipped it. I skipped it intentionally to make a bit of hyperbole.
An exception is still essentially a goto that crosses stack frames. There is a whole class of common bugs, you will see a lot of talk of them in the C and C++ communities, where an early return or a throw at an unexpected time leads to resources not being cleaned up. A lot of good coding styles say avoid this stuff, it's dangerous, and they are not without cause. Whereas a goto cleanup block is often a lot more explicit and therefore can lead to more reliable code than a scheme that encourages not sweating details and not expecting failure at every step.
They don't intend for label addresses to be gone to outside of the function they are located in. The stack wouldn't be setup to handle them at all.
Sure, you can store them wherever, and do something like " goto *g_greenthreads[ threadno ].lastpos ", but you would call that within the function defining the label, not outside it.
From your own link:
> You may not use this mechanism to jump to code in a different function. If you do that, totally unpredictable things will happen. The best way to avoid this is to store the label address only in automatic variables and never pass it as an argument.
I assumed the parent poster meant back before functionality was expressed as functions; i.e. it's sinful to jump from functionality A to functionality B if it's not expressed in terms of packaged functions, and impossible to do so if it is.
Dogmatically following so called rules in a cargo cult programming style without any understanding of the rationale behind them is many orders of magnitude more bad.
This form of blind programming is terribly dangerous. It takes focus away from the task and placed on the process.
Engage with the problem, engage with the computer. Do not engage with autocratic decrees and programming equivalencies of heretic and kosher.
Goto does something specific. If you need that specific thing then that's why it's there. Ceremonial rituals be damned
At a glance, looks like most of 'em are used for error handling. Sort of a `try ... finally` for C. This is actually a fairly common pattern -- check out Python's source code for more examples.
The other way I've seen it used is to break out of multiple levels of nested loops, though that's far less common.
`goto` is bad when it's used in an unstructured way: e.g. A does some stuff, then `goto B`. Then B does some stuff, then `goto C`. C sets a flag, does more stuff, then `goto B`. B does something different this time around based upon the flag set by C. Jumping around in a completely uncontrolled way such that the code can't be comprehended is where goto is "bad".
goto isn't inherently bad, it's just easy to use it in bad ways (and once upon a time, people did so more so than they generally do today -- which iirc was Dijkstra's major beef with it)
Linus himself has publicly said he doesn't mind appropriate gotos. "I think goto's are fine, and they are often more readable than large amounts of indentation." Mind you this was 11 years ago, and it's weird to quote him as some sort of oracle. But it seems relevant.
From that point on in the book, pretty much every function written has an "error:" label at the bottom where stuff gets cleaned up and memory freed. You can see his example code for it there.
Pretty useful macros, really. Context for the "goto considered harmful" always seems lost on young coders these days, unaware of the kind of spaghetti code that overuse of goto had caused.
Yeah, I've been on teams that have used this kind of error handling extensively, at several different companies. It's lightweight, very little is being done behind your back (do you know when your destructors are being called? really?) and it's easily inspected.
Also, never pass up the opportunity to troll a god-fearing "goto puritan" :-)
"Goto is bad" is something that professors tell first year computer science students because as computer scientists, the students will find novel ways of abusing them.
Using goto for error cleanup is pretty standard, easily readable, and understandable.
One of these days, "gotos: The Good Parts" will overshadow EWD's oft-abused essay, and the world will be spared highly nested, pointy-arrow C resource cleanup code.
I think what people are trying to say is that you shouldn't be taking too seriously all these advises about good and bad features in programming languages. Instead, try to understand the reasons behind such advises. All the bad things, that goto is blamed for, can be just as easily made with a bunch of methods in some object.
without a goto, you have to rely on functions/return values/pointers, which implies a function call (sometimes billions of times), which can have performance and design implications.
Because it is written in C. "Goto statements are bad" meant: lets start using languages that offer higher level constructs to replace the current usage of goto. Things like "loops" and "functions" and "exceptions". C did not get the memo.
C has loops and functions. But you're right that modern use of goto is typically used in error handling to replace specific use cases of exceptions in a primitive way (If error, goto end of function where cleanup is done before the return statement.)
> But you're right that modern use of goto is typically used in error handling to replace specific use cases of exceptions in a primitive way
Exactly. I pointed out the context of "goto considered harmful". Obviously the one that applies to C is the one that is the reason for all the gotos in C code.
How's that? To debug GOTOs you have to place breakpoints on each possible detection of error (or at a shared trampoline). To debug exceptions, you just enable first-chance exception handling for the kind of exception you're interested in and you're done.
The use cases for goto I see are primarily complex/thorough error handling (e.g. unwinding some concurrency control mechanisms) and certain low-level state machine patterns. I would expect to see these kinds of use cases in the Linux kernel.