I remember first using goto several years ago when I first started. I can see why it's not very pleasant to use as it could easily lead to spaghetti/confusing code. Though, it's still in the language for a reason. I recently saw something like this:
1 2 3 4 5 6 7 8
-- Pseudocode --
for (x -> 1000)
for (j -> 1000)
if (some_expression_is_true)
do_something();
goto Label;
Label:
I can see this person is using it to break out of multiple for-loops. Couldn't they use break; instead?
break would break out of the inner for loop (j) only. It wouldn't break out of the x loop. This can be done without using a goto using flags - but it can get messy
1 2 3 4 5 6 7 8 9 10 11 12 13
cont1 = truefor (x => 1000 while cont1)
for (j -> 1000 while cont1)
if (is_true)
do()
cont1 = false
endif
endfor j
endfor x
if (cont1 is false)
processfalse()
endif
In some circumstances (like this) a goto can be a cleaner method. I've used goto in parsing before to easily recover from an error.
break only breaks out of 1 layer of a loop (or switch statement).
I have never written a goto professionally (yet), but the most common -- but still very rare -- time I see goto used is when a function branches into many different paths, but most of the branches still clean something up or immediately handle a possible error condition before the function ends. I have seen this in mostly C-style C++ code. (A destructor would be an alternative here. Although I've heard people complain about destructors in cases like this because someone casually reading the code might not even realize key logic is happening in the destructor.) So pick your poison. Or instead of a goto, explicitly call a cleanup function + return.
Similar technique can be applied to nested loops. If you factor out the nested loop into its own function, you can call return while inside the nested loops, effectively doing the same thing as a goto.
Another way to avoid the goto in your example is to turn it into a function (or a lambda?)
1 2 3 4 5 6 7 8 9
void f() {
for (x -> 1000)
for (j -> 1000)
if (some_expression_is_true) {
do_something();
return;
}
}
}
Another way which I think would be cleaner is an obvious (to me anyway) addition to the language: let break be followed by one more more control keywords that give the structures it's breaking out of:
1 2 3 4 5
for (x -> 1000)
for (j -> 1000)
if (some_expression_is_true)
do_something();
breakforfor; // break out of both enclosing for loops.
The keywords would be optional. Without them, the behavior would be what we have today. Here are some more examples:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
while (cond) {
for (unsigned i=0; i<10; ++i) {
if (x) {
break; // today's behavior
} elseif (y) {
breakfor; // breaks out of for statement
} elseif (z) {
breakforwhile; // breaks out of for and while statements
} elseif (a) {
breakwhile; // syntax error: nearest enclosing breakable structure isn't a while
} elseif (b) {
breakwhilefor; // same as above
} elseif (c) {
breakforswitch; // syntax error: second enclosing breakable structure isn't a switch.
} elseif (d) {
breakforwhileswitch; // syntax error: the enclosing for and while structures aren't within a switch.
}
}
}
So break could be followed by a list of for, do, while and switch keywords. They must match the enclosed structures and, if they do, the break would break out of all of them.
I didn't know break would only break out of an inner loop, I figured as much but never tested it to find out (silly me). I think goto receives a lot of criticism and while they are justified most of the time, there are those rare times where goto can make your code clearer and improve performance.
@dhayden's I like that kind of addition to the language, I think it can make code more readable (sometimes perhaps), it does require you to look upwards and scan for keywords though.
I think people generally prefer to read top down. With goto, if used as discussed in this thread, you can continue looking downwards whereas with label_name you might need to scroll up to look for it.
its because early code, talking before 1990 and even back into the 70s, people had goto abuse that had you jumping all over the code everywhere and it was unreadable, couldn't be debugged easily, or modified easily -- everything people want to do with code normally (today) was in some way affected by the mess. Back then it was 1-2 guys who knew what was going on and so it was 'ok' because they knew what it did...
this behavior gave 'goto' and similar tools a bad name. They were pretty much banned from use (even when its fairly nice to do so) so much so that even your example makes some folks twist and turn the code every which way to avoid doing it. So much so that languages renamed it (eg break).