76

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;
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Nick Heiner
  • 119,074
  • 188
  • 476
  • 699
  • 2
    that's the wrong syntax for goto. just put your label outside the loops and don't put any breaks anywhere. – Jimmy Feb 26 '10 at 02:44
  • 1
    Duplicate: http://stackoverflow.com/questions/1586932/what-is-a-neat-way-of-breaking-out-of-many-for-loops-at-once – Foole Feb 26 '10 at 02:51
  • 1
    Consider: http://blogs.msdn.com/ericlippert/archive/2010/01/11/continuing-to-an-outer-loop.aspx – Eric Lippert Feb 26 '10 at 05:04
  • Eric -- Your blog is essential info for C# developers. Thanks so much for all the info you post there!!! – Bob Denny Feb 26 '10 at 05:32
  • possible duplicate of [Breaking out of a nested loop](http://stackoverflow.com/questions/324831/breaking-out-of-a-nested-loop) – Stewart Sep 17 '15 at 10:44
  • `Goto` is not that hideous. Maybe the labels don't look pretty, but from the code validity standpoint it's a case when it's justified. Of course unless `return` doesn't make it cleaner. Sometimes adding additional function call is MORE hideous than `goto`. You don't add a bunch of additional instructions just for the looks. – Harry Feb 03 '22 at 14:22

5 Answers5

93

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
  • 70,661
  • 7
  • 134
  • 187
  • 19
    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 Mar 09 '10 at 04:31
  • 28
    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 Mar 09 '10 at 07:53
  • I agree with this answer. One reason to put the nested loops into a separate function is that the original function is getting too big. If the original function is this big, the nested loops is a good place to break the function up into two functions. You have task A which is a series of nested loops, then you want to go to task B after the loops have found what they're looking for. If you feel having multiple returns is a problem, it's a sign your function is too big. – Russell Hankins Dec 05 '16 at 18:53
  • 2
    We are in 2018 C# have all the bells and whistless... But still no multilevel break or continue... – Calmarius Aug 14 '18 at 13:06
75

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
  • 6,405
  • 21
  • 29
  • 3
    +1 Very nice! :) I posted something sort of similar to this, but yours was better, so I deleted it. – Mark Carpenter Feb 26 '10 at 03:27
  • I wish I could vote for this more than once. The 'if(timeToStop && keepLooping)' can probably lose the 'keepLooping' part, other than that, brilliant! – Mark Carpenter Feb 26 '10 at 03:38
  • 2
    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 Mar 09 '10 at 04:31
  • Edited to remove the unnecessary keepLooping on the last loop like suggested by @Pwninstein – Fadrian Sudaman Mar 09 '10 at 05:16
  • 1
    @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 Mar 09 '10 at 05:21
  • lol, nothing tests the limits of structured programming more than parsing. – matt Mar 09 '10 at 06:57
  • If your loops are for statements, all you need to do is take the iterating value and set it to or higher than the max, you can do it for the current for but also each outer for... I had to do this when I had four nested FOR statements and needed to break out of the inner most two. – TravisO Mar 07 '19 at 15:57
  • But what if one of the upper whiles is foreach? Then even though foreach is over you will be keep looping until timeToStop occurs right? – İpek Jan 18 '22 at 11:45
29

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
  • 11,894
  • 12
  • 69
  • 85
  • 14
    +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 Feb 26 '10 at 02:38
  • 1
    IMO GOTO is only hideous when used outside assembly programming. To each his own, though :) – Mark Carpenter Feb 26 '10 at 03:35
  • From a structured programming point of view, goto is just a low-level construct on which the high-level constructs of selection and iteration are implemented. Return, break and continue break the structured programming module and are effectively just special cases of goto, but nonetheless I think the usefulness of them tends to win the day. – Stewart Sep 17 '15 at 10:18
3

You can just use goto to get out of the loops:

    [...]    
       while (true) {
            // ...
            while (shouldCont) {
                // ...
                while (shouldGo) {
                    // ...
                    if (timeToStop) {
                        goto GETOUT;
                    }
                }
            }
        } 
        GETOUT: 
        //move on to the next step
    [...]
    
schrdori
  • 51
  • 3
  • 1
    Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jul 06 '22 at 03:07
  • This is an excellent application of the goto statement. I would use this solution before any of the other ones. – brandonstrong Jul 22 '22 at 16:04
3

If you want to break out of an entire method, then use the code below. If you only want to break out of a series of loops within a method without breaking out of the method, then one of the answers that have already been posted will do the job.

if (TimeToStop)
{
   return;
}
Aaron
  • 1,390
  • 1
  • 16
  • 30
tolu619
  • 31
  • 1