tags:

views:

437

answers:

4

What if I have nested loops, and I want to break out of all of them at once?

while (true) {
    // ...
    while (shouldCont) {
        // ...
        while (shouldGo) {
            // ...
            if (timeToStop) { 
                break; // break out of everything?
            }
        }  
    }
}

In PHP, break takes an argument for the number of loops to break out of. Can something like this be done in C#?

What about something hideous, like goto?

// in the innermost loop
goto BREAK
// ...
BREAK: break; break; break;
+11  A: 

Goto is only hideous when abused. To drop out of the innermost loop of some nesting it's acceptable. BUT... one has to ask why there is so much nesting there in the first place.

Short answer: No.

Andrew
+1. Basically, every control structure is `goto` underneath; just fitted into a specific purpose. For everything that *isn't* covered by those special purposes there is no other “elegant” option than `goto`.
Joey
IMO GOTO is only hideous when used outside assembly programming. To each his own, though :)
Pwninstein
+22  A: 

Extract your nested loops into a function and then you can use return to get out of the loop from anywhere, rather than break.

Michael Anderson
that's a hack, not what functions are for, most people who hate goto consider early returns in functions just as bad. I disagree with such broad sweeping statements, but I would say that using goto is just as valid as this solution to the problem, though certainly not as neat.
matt
I disagree entirely matt. The number of people who believe in requiring a single exit from functions is _much_ smaller than those who hate gotos. The reason is that in many languages goto doesn't perform correct resource cleanup (dont know about C# for sure) but return does. Also IMHO functions are for grouping, scoping and simplifying related code. That's exactly what this does.
Michael Anderson
A: 

You could pull some shenanigans and do something like this:

try{
    while (true) {
        // ...
        while (shouldCont) {
            // ...
            while (shouldGo) {
                // ...
                if (timeToStop) { 
                    throw new EndOfLoopException();
                }
            }  
        }
    }
} catch (EndOfLoopException) { }

The exception will be caught and the rest of the function will execute normally. Obviously, exceptions should be thrown when something BAD happens, but if you literally cannot extract this into a separate function, then I would probably recommend this over GOTO's anyday.

Pwninstein
Use of exceptions for control flow is worse than using a GOTO. You incur all the extra cost of constructing the exception, then the cost of having it be thrown AND caught!
jrista
You gotta be kidding!
Felipe Lima
I disagree. With GOGO's there's no logical flow AT ALL, you can redirect execution to anywhere within the function! try...catch blocks are scoped, and only have two possible outputs: the end of the 'try' or the end of the 'catch'.
Pwninstein
This fails the *principle of least astonishment*.
Scott Smith
This is a valid solution. To some it might be "pretty" while to others it might be hideous. Gotos don't have logical flow. His code actually shows some sort of logic. Although I don't see why you would want to implement what he wrote, I have to admit his method is WAAY better than Goto, while also "getting to the point"... the logic is extremely clear, in my opinion. The only bad part is the overhead. You can optimize later.
ItzWarty
@ltzWarty "The only bad part is the overhead" - I agree. I would try to never end up in this situation in the first place. Hence "shenanigans." :)
Pwninstein
@Pwinstein: "With GOGO's there's no logical flow AT ALL". I would disagree with that as a blanket statement. A goto is as logical as you make it. In the case of breaking out of nested loops, I believe goto's are both logical and valid.
jrista
Of course, by 'GOGO' I meant 'GOTO' *facepalm*, though I still hold the same opinion about them (never use them outside assembly programming).
Pwninstein
+6  A: 

Introduce another control flag and put it in all your nested while condition like below. Also replaces the while(true) condition you have with that

bool keepLooping = true;
while (keepLooping) {
    // ...
    while (shouldCont && keepLooping) {
        // ...
        while (shouldGo && keepLooping) {
            // ...
            if (timeToStop) { 
                keepLooping  = false;
                break; // break out of everything?
            }
        }  
    }
}
Fadrian Sudaman
+1 Very nice! :) I posted something sort of similar to this, but yours was better, so I deleted it.
Pwninstein
Pwninstein
I don't get it, how is this any easier to read than goto? you have to come up with a variable name that describes the intention of it to break out of all the loops, why don't you just put the same effort into coming up with a name for a goto label? this is after all slower. you have to look for everywhere that keepLooking is used, not just one label.
matt
Edited to remove the unnecessary keepLooping on the last loop like suggested by @Pwninstein
Fadrian Sudaman
@Matt - Certainly you can do the same and personal preference I will use the above over GOTO. In this scenario, GOTO can be just as readable, but in many cases GOTO can make code very unreadable and really not advisable in structure programming environment. Most coding guidelines I have seen have been stirring away from it and why break it for a simple structure problem like above? The only time I have used GOTO and find it really useful is when I wrote a complex parser where I need to interpret token against hundreds of keywords with some interesting repeating logic.
Fadrian Sudaman
lol, nothing tests the limits of structured programming more than parsing.
matt