I suggest you ...

Allow the C# 'break' statement to terminate *several* nested enslosing loops, rather than the closest one only

Sometimes, I want to exit several nested loops, based on a single condition.

Today, I have to introduce an additional boolean variable, to exit all the other loops except the innermost one. This is inconvenient.

If only the 'break' statement could have accepted the number of loops to break...

A straighforward example:
for(;;)
{
for(;;)
{
if{true} break(2);
}
}

This feature would work just similarly when used in a 'switch' statement.

We would only have to be concerned to not allow the 'break's parameter to exceed the number of nested scopes it is used from within. Otherwise, an error should be thrown. :-)

38 votes
Vote
Sign in
Check!
(thinking…)
Reset
or sign in with
  • facebook
  • google
    Password icon
    I agree to the terms of service
    Signed in as (Sign out)
    You have left! (?) (thinking…)
    Maksym NikulyakMaksym Nikulyak shared this idea  ·   ·  Flag idea as inappropriate…  ·  Admin →

    12 comments

    Sign in
    Check!
    (thinking…)
    Reset
    or sign in with
    • facebook
    • google
      Password icon
      I agree to the terms of service
      Signed in as (Sign out)
      Submitting...
      • Maksym NikulyakMaksym Nikulyak commented  ·   ·  Flag as inappropriate

        DaryI, I support your idea; only, to give such loop control statements just enough power, I would allow them to use only the *specialized* (i.e., loop) labels, rather than the existent, general-purpose ones.

        Thinking further of such loop labels, I would suggest that, maybe, they should be made an optional part of the loop syntax - e.g., like this:

        foreach (string fileName in fileList) as MyFileLoop {...}

      • DarylDaryl commented  ·   ·  Flag as inappropriate

        A much better option, which other languages support, is to use labels. See this suggestion:

        https://visualstudio.uservoice.com/forums/121579-visual-studio-2015/suggestions/10479150-support-labels-on-loop-control-statements

        FileLoop:
        foreach (string fileName in fileList)
        {
        for (;;)
        {
        while (true)
        {
        if (someCondition) continue FileLoop; // done with this file
        }
        }
        }

        PROS:

        This is much safer than goto -- if the label doesn't refer to a loop statement, using break or continue is a compile-time error.

        More maintainable -- counting loop levels and using an int is asking for trouble. Someone might add a loop level without noticing the break(2). Or remove a loop level. Or copy the code with the break(2) to a different place... etc. This is a bad idea.

        Works with existing syntax. The new syntax is a proper superset of the existing syntax. No lexical weirdness like they had with "async" and LINQ would be needed.

      • Maksym NikulyakMaksym Nikulyak commented  ·   ·  Flag as inappropriate

        I very much like the amendment that Viktor Zakharov has suggested; to me, it's the best of the proposed variants, and 100% robust on its own right.
        And I like the offered syntax, "break for[n]"

      • Victor ZakharovVictor Zakharov commented  ·   ·  Flag as inappropriate

        I think it makes more sense to have syntax like "break for[1]", which means a second "for" (0-based index). This can expand to 10 nested loops, where you have all sorts of while/for/do mess, and will still work after refactoring. Compiler can throw an error, if the scope you are trying to reference is no longer available.

      • AdamAdam commented  ·   ·  Flag as inappropriate

        If you are goto adverse, I'd argue a lambda might make more sense than wrapping the code in a function. That way, the closure captures the needed data without needing lots of function parameters.

        In either case, breaking 'n' levels deep is extremely fragile and prone to error. If you are writing code that looks like this, you probably are in need of a refactor anyway if you expect someone else to be able to reason about your code.

      • Matthew RicksMatthew Ricks commented  ·   ·  Flag as inappropriate

        I'd prefer it if it were break n instead of break(n) because that (to me) maintains the break keyword usage.

        There's nothing wrong with extra variables, but sometimes they're flags that just add clutter. I think the break n could easily be more readable. Potentially abused? Yes, but we can deal with that.

        I understand the switch/loop confusion, but I don't think it's that big a deal. It's pretty obvious if the break is at the level of a switch, and usually obvious if it's breaking a loop. I think standardizing that break n only breaks loops solves the issue.

        Could definitely refactor, but sometimes it doesn't make sense to break it out into a separate method.

        And, unless I miss my mark, goto is more likely to make code fragile than this feature.

      • PhilippePhilippe commented  ·   ·  Flag as inappropriate

        That feature make the code very fragile to change. As indicated by other, much more better to use goto instead.

        On the other hand, you might be able to refactor the code so that the loop are Inside another function and then you can use return two levels higher...

        By the way if switch and loop are mixed, it would be very confusing. Also how would you handle the case where you want to break first loop and continue outer one?

        Finally, there is nothing wrong with using extra variables to control the flow.

      • Maksym NikulyakMaksym Nikulyak commented  ·   ·  Flag as inappropriate

        Re comment by Pascal Craponne:

        > this feature already exists and is called goto :)
        > (which in this case is as good as break)

        Dear Sir, we all dislike 'goto' for its enormous power, don't we? For this reason, 'goto' is much worse than 'break' - and in this case, too...

        I stand for solving any problem with just the right means - and, from this viepoint, introducing 'break(n)' would be just right. More so because, as much as I understand the phylosophy of C#, this language praises "just right remedies" more than it does the size of the language.

      • Maksym NikulyakMaksym Nikulyak commented  ·   ·  Flag as inappropriate

        Re comment by Andras Daniel Toth:

        Thank you, Sir, your approach does solve the issue.
        But... Isn't it posing a bigger one? - I mean that introducing a function may bring a greater overhead (both during the execution time and the programming time;-), than using just one boolean flag variable to break the outer loops. - Especially so when the inner loops are "variable intensive".

      • Andras Daniel TothAndras Daniel Toth commented  ·   ·  Flag as inappropriate

        Why don't you refactor these loops into a method? Then you can use 'return'.

        public Stuff DoingMyNestedLoop()
        {
        for
        {
        for
        {
        if (true) return stuff;
        }
        }
        }

        usage:
        for (;;)
        {
        DoingMyNestedLoop();
        }

        It will exit all inner loops except for your only outer loop. :)

      Feedback and Knowledge Base