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.
I'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.
Your 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.
goto 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.
When I teach this stuff, I try to distinguish between
(1) Returning/Exiting/Excepting because of a legitimate error condition
(2) Returning/Breaking early because there's either no work to do or something necessary to do the work is absent/unavailable (the latter often turns into a case of (1)
(3) Returning/Breaking/Continuing early because I've discovered the work is done for either all iterations or this particular iteration, and the remainder of the function/method/loop is pointless cycling. (Often added during optimization, sometimes added too early).
(4) Returning/breaking/GOTOing because I've gotten confused and want to go to a place in the code that makes more sense to me. This is the only that's actually a problem and should be railed against. Unfortunately, it's way more common than it really should be in beginners' programs. I think GOTO got an early bad rap---try writing non-trivial machine code or assembler without liberal use of goto, and many very useful techniques in debugging are basically informed application of goto---because of what I call the "pull the ejection handle" approach to getting into trouble trying to code an algorithm you dont really understand.
I love all those "goto" disguised as any kind of flow controls. Because goto is devil, but give it another name and another smell and, voilà!, it becomes beautiful.
Yes. Because giving it a different name addresses the problem with goto.
The problem with goto is that it is opaque. It has no structure, it has no constraints, and it communicates no intent. It says "execute the code behind this label," and gives no clue what the code is or what it does.
But if you give goto a different name that reflects how you're using it, that solves the problem! If your goto is named "break" and it occurs inside a loop, that tells you what the goto is trying to achieve. It tells you at a glance what code you expect to find when you jump, and its relationship to the other code in the program. In short, it communicates intent.
The same is true when the name is "continue" or "throw": you know where in the program that goto leads and what sort of code you expect to find when you go there. You don't need to read it to find out. And if you do read it, you have a better idea of whether it's right or not.
(Also note that criticism of goto applies a lot more to historical gotos, whose argument was an arbitrary memory address. Modern gotos aren't nearly as bad because they generally take a label rather than a number, and because their jump targets are often restricted to the immediate lexical environment.)
I encountered one of these beautiful things you mention not too long ago.
void foo()
{
do {
for (...) {
if (...) {
break;
}
}
if (...) {
...
if (...) {
...
break;
}
}
/* even more nested loops and conditionals with break sprinkled all over */
} while (0);
...
}
PS: IMHO this code goes too far with the "goto considered harmful" philosophy. The "while (0)" is serving the purpose of a label. An explicit label instead would be more readable, IMHO.
At a hardware level all control flow is made up of gotos. But by writing them as 'for' or 'break' or 'if' in our programs we make them easier to read by letting the reader know that the jump is restricted in certain ways.
Its really not that hard. Instead of blindly following rules someone else wrote, just read the code. Is it easy to follow? How many details do you have to juggle in your head? How many indented scopes are there? How much state is there? Can you mostly read it from top to bottom, or do you constantly have to jump around the file? If someone unfamiliar with the code (maybe you in 3 months) needs to make a change, how easy would it be for them to overlook some important detail and mess it up?
Best practices usually apply in general, but the smart person who coined them cannot know all possible situations and the parrots who blindly repeat them don't know what they're talking about. Think for yourself, know your tools, and use them effectively to make your code as simple as possible.
Just use functions calls already. Modern languages and compilers / interpreters have gotten good enough (at least the ones that care), that there's no need to bless a small set of control structures by being special-purpose built-in.
This is relevant. There are lots of real-life errors that come out of these errors and the worse mistakes people make trying to work around control flow (goto fail?).
I desperately want a 'break break' command. Not a label break, which is painful to work with, but an instruction to break the current loop and the outer loop.
I don't like the goto fail thing being discussed as an example of goto being evil. If they had used the other common pattern - returning -1 on failure - instead of the pattern they used, their code would look like this:
if (a)
return -1;
if (b)
return -1;
return -1;
if (c)
return -1;
return 0;
And literally the exact same issue would occur, even though goto wasn't used.
[+] [-] glangdale|8 years ago|reply
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.
[+] [-] userbinator|8 years ago|reply
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.
[+] [-] mcguire|8 years ago|reply
[+] [-] dbaupp|8 years ago|reply
Of course, thinking about labelled break is just dreaming when required/choosing to work in a language without it.
[+] [-] mjevans|8 years ago|reply
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.
[+] [-] ajarmst|8 years ago|reply
[+] [-] woliveirajr|8 years ago|reply
[+] [-] lmkg|8 years ago|reply
The problem with goto is that it is opaque. It has no structure, it has no constraints, and it communicates no intent. It says "execute the code behind this label," and gives no clue what the code is or what it does.
But if you give goto a different name that reflects how you're using it, that solves the problem! If your goto is named "break" and it occurs inside a loop, that tells you what the goto is trying to achieve. It tells you at a glance what code you expect to find when you jump, and its relationship to the other code in the program. In short, it communicates intent.
The same is true when the name is "continue" or "throw": you know where in the program that goto leads and what sort of code you expect to find when you go there. You don't need to read it to find out. And if you do read it, you have a better idea of whether it's right or not.
(Also note that criticism of goto applies a lot more to historical gotos, whose argument was an arbitrary memory address. Modern gotos aren't nearly as bad because they generally take a label rather than a number, and because their jump targets are often restricted to the immediate lexical environment.)
[+] [-] sigjuice|8 years ago|reply
[+] [-] Symmetry|8 years ago|reply
[+] [-] cabaalis|8 years ago|reply
2. Is the code relatively readable by someone unfamiliar with the problem?
If 1 && 2 then stop tearing your robes like Pharisees and go solve another problem.
[+] [-] graycat|8 years ago|reply
[+] [-] mcguire|8 years ago|reply
Some people seem determined to cause facial tics in everyone they meet.
[+] [-] fmatthew5876|8 years ago|reply
Best practices usually apply in general, but the smart person who coined them cannot know all possible situations and the parrots who blindly repeat them don't know what they're talking about. Think for yourself, know your tools, and use them effectively to make your code as simple as possible.
[+] [-] eru|8 years ago|reply
[+] [-] mcguire|8 years ago|reply
[+] [-] awinter-py|8 years ago|reply
I desperately want a 'break break' command. Not a label break, which is painful to work with, but an instruction to break the current loop and the outer loop.
[+] [-] mort96|8 years ago|reply
[+] [-] danthemanvsqz|8 years ago|reply
[+] [-] lacampbell|8 years ago|reply
[+] [-] erikpukinskis|8 years ago|reply
[+] [-] btilly|8 years ago|reply
[+] [-] GrumpyNl|8 years ago|reply
[+] [-] tuukkah|8 years ago|reply