Have you ever considered break( n ) ?

356 views
Skip to first unread message

amg...@gmail.com

unread,
Sep 8, 2016, 7:54:14 AM9/8/16
to ISO C++ Standard - Future Proposals
    In order to exit from a nested loop when a condition is found you need to add an extra condition to ckeck in each external loop:


    while ( cond1 )
    {
        bool found = false;
        while ( cond2 )
        {
            if ( cond3 )
            {
                found = true;
                break;
            }
        }

        if ( found )
        {
            break;
        }  
    }


    solution 1 ) elegant but slow to code: declare a new method, move that double bucle to that method and use return
   

    void    test()
    {
        while ( cond1 )
        {
            while ( cond2 )
            {
                if ( cond3 )
                {
                    return
;               
                }
            }           
        }
    }

    solution 2 ) use goto ( faster to code but uglier style )
   
    https://msdn.microsoft.com/en-us/library/b34dt9cd.aspx?f=255&MSPPError=-2147217396

    "It is good programming style to use the break, continue, and return statements instead of the goto statement whenever possible. However, because the break statement exits from only one level of a loop, you might have to use a goto statement to exit a deeply nested loop."

    while ( cond1 )
    {
        while ( cond2 )
        {
            if ( cond3 )
            {        
                goto LabelEndLoops;
            }
        }
    }

    LabelEndLoops;


    solution 3 ) proposal... break( n )

    while ( cond1 )
    {       
        while ( cond2 )
        {
            if ( cond3 )
            {
                break( 2 );
            }
        }
    }

    This is very simple to solve by compiler, it just needs to replace internally by a goto statement.

        break( 1 ) = break  exits from 1 loop
        break( n ) exits from n loops
        break( * ) exits from all loops

    or if you prefer break1, breakN, break* without the parenthesis instead is also acceptable.
    ( In case of symbol * cannot be used, it can be replaced by any more convenient. )

Larry Evans

unread,
Sep 8, 2016, 8:12:02 AM9/8/16
to std-pr...@isocpp.org
On 09/08/2016 06:54 AM, amg...@gmail.com wrote:
[snip]
> "It is good programming style to use the break, continue, and return
> statements instead of the goto statement whenever possible. However,
> because the break statement exits from only one level of a loop, you
> might have to use a goto statement to exit a deeply nested loop."
>
> while ( cond1 )
> {
> while ( cond2 )
> {
> if ( cond3 )
> {
> *goto LabelEndLoops;*
> }
> }**
> }
>
> * LabelEndLoops;*
>
>
> ***solution 3 )* proposal...break( n )
>
> while ( cond1 )
> {
> while ( cond2 )
> {
> if ( cond3 )
> {
> *break( 2 ); *
> }
> }
> }
>
> This is very simple to solve by compiler, it just needs to replace
> internally by a goto statement.
>
> *break( 1 )* = *break* exits from 1 loop
> *break( n )* exits from n loops
> *break( * )* exits from all loops
>
[snip]

Years ago (1980's or maybe 1970's) there was an article
describing a language with, instead of:

break(levels_to_exit)

it was

exit(levels_to_exit)

and I think just a loop keyword. The article showed how to
transform any goto program to one just using this exit and
loop and if-then-else.

I've tried to find the reference without success. I'll
continue looking if anyone's interested.

-regards,
Larry


Klaim - Joël Lamotte

unread,
Sep 8, 2016, 8:16:05 AM9/8/16
to std-pr...@isocpp.org
It was considered I think at least 2 times in very long threads in the last 2 years in this very discussion group.
You should be able to find it by searching "break" with another keyword.




--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/nqrkga%24hgr%241%40blaine.gmane.org.

Ville Voutilainen

unread,
Sep 8, 2016, 8:17:36 AM9/8/16
to ISO C++ Standard - Future Proposals
On 8 September 2016 at 15:16, Klaim - Joël Lamotte <mjk...@gmail.com> wrote:
> It was considered I think at least 2 times in very long threads in the last
> 2 years in this very discussion group.
> You should be able to find it by searching "break" with another keyword.


Also, this paper http://open-std.org/JTC1/SC22/WG21/docs/papers/2014/n3879.pdf
was discussed and rejected in Rapperswil.

amg...@gmail.com

unread,
Sep 8, 2016, 8:30:11 AM9/8/16
to ISO C++ Standard - Future Proposals
Well that paper proposal allows "break" with an optional identifier which needs to define an extra label, therefore is very similar to a goto. Don't make sense to me.

This is about exiting loops easily with just an optional number telling how many loops exit.

Klaim - Joël Lamotte

unread,
Sep 8, 2016, 8:39:49 AM9/8/16
to std-pr...@isocpp.org

On 8 September 2016 at 14:30, <amg...@gmail.com> wrote:
This is about exiting loops easily with just an optional number telling how many loops exit.

I remember that this option was discussed a lot because it cause the break to have a relative meaning, which does not work well with code that change.
The discussion converged to a preference to a way to name the section of the code (either label or an alternativ) which is associated to the break.

amg...@gmail.com

unread,
Sep 8, 2016, 8:55:12 AM9/8/16
to ISO C++ Standard - Future Proposals
"break" already has a relative meaning, it is relative to current loop. This just extends to more than one, no need of labels otherwise we already have "goto".

Klaim - Joël Lamotte

unread,
Sep 8, 2016, 9:07:09 AM9/8/16
to std-pr...@isocpp.org
On 8 September 2016 at 14:55, <amg...@gmail.com> wrote:
"break" already has a relative meaning, it is relative to current loop. This just extends to more than one, no need of labels otherwise we already have "goto".


If you use numbers to express how many scopes to break from, then it's a relative break. If you name the scope to exit from, it's not relative at all.
 

On Thursday, September 8, 2016 at 2:39:49 PM UTC+2, Klaim - Joël Lamotte wrote:

On 8 September 2016 at 14:30, <amg...@gmail.com> wrote:
This is about exiting loops easily with just an optional number telling how many loops exit.

I remember that this option was discussed a lot because it cause the break to have a relative meaning, which does not work well with code that change.
The discussion converged to a preference to a way to name the section of the code (either label or an alternativ) which is associated to the break.

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.

amg...@gmail.com

unread,
Sep 8, 2016, 9:29:30 AM9/8/16
to ISO C++ Standard - Future Proposals
There is already a implicit number of 1 in the break, so the standard c++ break it is already a relative break, this do not changes the behaviour, just extends it.



On Thursday, September 8, 2016 at 3:07:09 PM UTC+2, Klaim - Joël Lamotte wrote:
On 8 September 2016 at 14:55, <amg...@gmail.com> wrote:
"break" already has a relative meaning, it is relative to current loop. This just extends to more than one, no need of labels otherwise we already have "goto".


If you use numbers to express how many scopes to break from, then it's a relative break. If you name the scope to exit from, it's not relative at all.
 

On Thursday, September 8, 2016 at 2:39:49 PM UTC+2, Klaim - Joël Lamotte wrote:

On 8 September 2016 at 14:30, <amg...@gmail.com> wrote:
This is about exiting loops easily with just an optional number telling how many loops exit.

I remember that this option was discussed a lot because it cause the break to have a relative meaning, which does not work well with code that change.
The discussion converged to a preference to a way to name the section of the code (either label or an alternativ) which is associated to the break.

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.

To post to this group, send email to std-pr...@isocpp.org.

Nicol Bolas

unread,
Sep 8, 2016, 9:32:59 AM9/8/16
to ISO C++ Standard - Future Proposals, amg...@gmail.com

Personally, I feel like cases like this are sufficiently rare that `goto` usage is perfectly acceptable. `goto` is for exceptional circumstances, and this is one of them.

Also, `goto` feels safer in these cases, for two reasons:

1. You can easily find exactly where the `goto` will go. Whereas if you have compound looping constructs, your code is likely growing quite large. So finding where a `break(3)` statement will go will be difficult.

2. If you add another level of looping, which is entirely possible considering that you have 2 or more already, your `goto` will still go to the same place. Whereas you have to find all your `break(2)` statements and turn them into `break(3)`.

amg...@gmail.com

unread,
Sep 8, 2016, 10:36:05 AM9/8/16
to ISO C++ Standard - Future Proposals, amg...@gmail.com
Problem is these cases are not so rare. Everything that is composed of more than 1 dimension, like images, databases, matrixes, etc, requieres 2 or more loops to apply most of algorithms to them ( usually everything composed of row and columns )
for example: to search for an element and abort when the condition is found. There is a lot of algorithms than needs to deal with mutliple dimensional objects, so this situation is a lot more frequent than expected.

Anyway this not about replacing goto, anyone can keep using it, though similar problems you describes applies to goto too:
If algorithm is modified or adjusted it may requiere the label to be moved, otherwise algorithm will fail aswell.
If I do break( 2 ) i know exactly how many loops I exit. If I do a goto, can be anywhere in the method, even in previous lines, so finding where label is located can be even harder.

Besides adding an external loop, do not forces to have to increase break( 2 ) to break( 3 ), if algorithm is looping an image, that image is 2-dimensional and it will keep break( 2 ).
At the end depending on the algorithm the exit of the loops with a break( n ) it is more suitable than the goto generic behaviour ( it goes anywhere ) is not specific for breaking, just used because we have no other better choice.

Peter Koch Larsen

unread,
Sep 8, 2016, 10:52:21 AM9/8/16
to std-pr...@isocpp.org
One problem with this proposal is that it promotes bad code. Sean
Parent has the good advice to avoid raw loops. To provide facilities
that support multiple nested loops is a step in the wrong direction.
In the rare case where you can not split your nested loop into two or
more functions just use the goto statement which will also serve as a
reminder that this is an area of code where you have to be extra
careful if you change anything.

Peter Koch Larsen

unread,
Sep 8, 2016, 10:57:00 AM9/8/16
to std-pr...@isocpp.org
On Thu, Sep 8, 2016 at 4:36 PM, <amg...@gmail.com> wrote:
> Problem is these cases are not so rare. Everything that is composed of more
> than 1 dimension, like images, databases, matrixes, etc, requieres 2 or more
> loops to apply most of algorithms to them ( usually everything composed of
> row and columns )
> for example: to search for an element and abort when the condition is found.
> There is a lot of algorithms than needs to deal with mutliple dimensional
> objects, so this situation is a lot more frequent than expected.
>
You do not need multiple loops to search for an element. You do not
need any raw loop at all, actually. Just use std::find_if.

/Peter

D. B.

unread,
Sep 8, 2016, 10:59:07 AM9/8/16
to std-pr...@isocpp.org
On Thu, Sep 8, 2016 at 3:52 PM, Peter Koch Larsen <peter.ko...@gmail.com> wrote:

One problem with this proposal is that it promotes bad code. Sean
Parent has the good advice to avoid raw loops. To provide facilities
that support multiple nested loops is a step in the wrong  direction.
In the rare case where you can not split your nested loop into two or
more functions just use the goto statement which will also serve as a
reminder that this is an area of code where you have to be extra
careful if you change anything.


This. The idea of 'relative break' based on some magic number of loop levels is so brittle that it makes me wince.

GOTO is not inherently bad, just not used in the right places in most cases. This is exactly such a place. It means you can have a labelled, less fragile exit point.

amg...@gmail.com

unread,
Sep 8, 2016, 11:14:24 AM9/8/16
to ISO C++ Standard - Future Proposals
Was trying to show an easy example, you can find infinite algorithms looping an image looking for certain cummulative conditions that you cannot use a simple templated std method to locate them, and needs specific algorithm.

amg...@gmail.com

unread,
Sep 8, 2016, 11:59:09 AM9/8/16
to ISO C++ Standard - Future Proposals
You probably didn't realize that c++ break is already relative, it exits from the current loop level. Where it exits? relative to the size of the loop where you put the break. If the loop would have 1 thousand lines, it would jump at the end to that code length.
'break' behaviour is very useful, so this break(n) extension is not different.

Besides it's safer than it looks like:
With break(n) you can't go anywhere, you can't go backwards, you can't go any other nested loop where it belongs. Just can continue at the end of own nested loops.
And compiler can easily see if you try to break with a higher number than existant loops and report.

And let's be clear and practical, how many nested loops do we have? 1, 2, ... 3? other than that we split in other method, so we are not going to use break( 17 ), aswell we can place one thousand goto's in a method but nobody does it.
As you say GOTO is not inherently bad, I agree because at the end this is coder responsability to create a good code or bad one, is not just the instructions.
Pointers are potentially really dangerous, bad handled dynamic memory is, unions are, etc... but we use them, welcome to C++.

break(n) is useful, clear, requieres no extra conditional check or define extra label like goto, and it is easy to implement by compiler. It can be translated with an internal goto, but transparent and safe, aswell it does with the usual jumps in conditionals "if/else", "for", "do / while", etc

And the most important, it is optional, you can use it or not.

Nicol Bolas

unread,
Sep 8, 2016, 1:39:39 PM9/8/16
to ISO C++ Standard - Future Proposals, amg...@gmail.com
On Thursday, September 8, 2016 at 10:36:05 AM UTC-4, amg...@gmail.com wrote:
Problem is these cases are not so rare. Everything that is composed of more than 1 dimension, like images, databases, matrixes, etc, requieres 2 or more loops to apply most of algorithms to them ( usually everything composed of row and columns )
for example: to search for an element and abort when the condition is found. There is a lot of algorithms than needs to deal with mutliple dimensional objects, so this situation is a lot more frequent than expected.

That sounds like a good reason to have a multidimensional iterator type so that you can use `find_if`, not a first-class language feature.

And as you mention later, yes, there are other scenarios that cannot be handled by a generic algorithm, even with a multi-dimensional iterator. But again, such scenarios are so rare (made even moreso with multidimensional iterators) that they're not worth adding a language feature to solve them. Not so long as we already have a language feature that can handle it adequately.

Anyway this not about replacing goto, anyone can keep using it, though similar problems you describes applies to goto too:
If algorithm is modified or adjusted it may requiere the label to be moved, otherwise algorithm will fail aswell.
If I do break( 2 ) i know exactly how many loops I exit. If I do a goto, can be anywhere in the method, even in previous lines, so finding where label is located can be even harder.

Finding a `goto` label is done via a simple string search. A good IDE can give it to you by simply right-clicking and picking a menu-item, or with a keyboard shortcut. Finding where `break 2` goes require finding the two nearest loops, which may be off-screen.

On Thursday, September 8, 2016 at 11:59:09 AM UTC-4, amg...@gmail.com wrote:
You probably didn't realize that c++ break is already relative, it exits from the current loop level. Where it exits? relative to the size of the loop where you put the break. If the loop would have 1 thousand lines, it would jump at the end to that code length.
'break' behaviour is very useful, so this break(n) extension is not different.

You can't just say that your feature is just as good as another, more narrow feature, just because it does what the narrow feature does too.

`break` is tolerated precisely because it is narrow. It has its fragilities, but doing a single jump out of a loop solves more problems than it causes. The problems that `break(X)` solve are so rare that they're not worth the problems that having such a feature will cause.

And let's be clear and practical, how many nested loops do we have? 1, 2, ... 3? other than that we split in other method, so we are not going to use break( 17 ), aswell we can place one thousand goto's in a method but nobody does it.

... You seem to be arguing against your own feature. If you genuinely only have 2 or 3 dimensions on such loops, then what's the point of this "break-by-number" functionality?

break(n) is useful, clear, requieres no extra conditional check or define extra label like goto, and it is easy to implement by compiler. It can be translated with an internal goto, but transparent and safe, aswell it does with the usual jumps in conditionals "if/else", "for", "do / while", etc
 
And the most important, it is optional, you can use it or not.

Every language feature has a cost. It costs times for the committee to evaluate and standardize a proposal. It costs compiler writers time to implement it. It costs teaching time when users unfamiliar with it ask about it.

Whether you personally use a language feature or not, you will still pay these costs.

As such, any language feature must provide sufficient benefit, broadly, to be worth that cost. To me, your proposal fails in two areas:

1. The amount of code that would benefit from its use is not significant enough to be worth the costs of having it as a feature. While the existing solutions are not ideal, they are adequate for those times when the problem arises.

2. The use of this feature encourages the writing of low-quality code.

Oh, and there's another thing that makes your idea problematic. It doesn't combine well with the proposal for a "for/else" mechanism. What would happen if you use `break(2)` and the inner loop has an `else` clause (or whatever we want to call it)? By limiting `break` to just one loop, we ensure that such a proposal still makes sense.

amg...@gmail.com

unread,
Sep 8, 2016, 2:25:11 PM9/8/16
to ISO C++ Standard - Future Proposals, amg...@gmail.com
Finding a `goto` label is done via a simple string search. A good IDE can give it to you by simply right-clicking and picking a menu-item, or with a keyboard shortcut. Finding where `break 2` goes require finding the two nearest loops, which may be off-screen.

Well, this is going to a too much more complicated issue that it started. If you see my initial example, it is very simple, you do not need a 3 page code to make use of it. What I mean is, if the code containing the inner loops is complex enough you should split that code into another method containing the loops, and this way you solve both: the break will be replaced by a return, and the complexity of the method will decrease by splling it.

But, as my example, if code is small enough due to inner code loops are simple, you want a clean and fast exit. Splitting the method is discarded in this case, so you only can use the goto or adding extra conditions.
That's why i proposed this break(n). The "goto" is not the more desirable to use, either you want dirtier code with these extra conditions.
In fact I proposed the generic break(n), but probably with a break2 and a break3 would be enough, as I said before, with a higher inner loops you should split it.
This way it keeps simpler.




2. The use of this feature encourages the writing of low-quality code.

I don't see this as encouraging low-quality code, this way unnecessary conditions aren't requiered, keep using the same keyword designed to break loops, and also do not requieres the goto, which is worse and depends on extra label.



Oh, and there's another thing that makes your idea problematic. It doesn't combine well with the proposal for a "for/else" mechanism. What would happen if you use `break(2)` and the inner loop has an `else` clause (or whatever we want to call it)? By limiting `break` to just one loop, we ensure that such a proposal still makes sense.


I didn't know that proposal, but looks already incompatible by using goto inside isn't? My proposal isn't incompatible with anything because internally it can be translated to a goto by the compiler.



szollos...@gmail.com

unread,
Sep 8, 2016, 2:26:19 PM9/8/16
to ISO C++ Standard - Future Proposals, amg...@gmail.com
Hi,

Note that this is essentially solved by the idea of 'capturing monads in lambdas'.

Thanks,
-lorro

Larry Evans

unread,
Sep 8, 2016, 4:49:00 PM9/8/16
to std-pr...@isocpp.org
On 09/08/2016 07:55 AM, amg...@gmail.com wrote:
> "break" already has a relative meaning, it is relative to current loop.
> This just extends to more than one, no need of labels otherwise we
> already have "goto".
>
>
In http://open-std.org/JTC1/SC22/WG21/docs/papers/2014/n3879.pdf, the
loop_label in:

break loop_label;

must label an existing loop; hence, is different than:

goto statement_label;

where statement_label can label *any* statement.
At least that's how I read section 0.5.1 in n3879.pdf.

-regards,
Larry





amg...@gmail.com

unread,
Sep 8, 2016, 7:47:30 PM9/8/16
to ISO C++ Standard - Future Proposals, cpplj...@suddenlink.net
Ok, I just wanted to let know my proposal.

These previous attempts like this "explicit flow control" paper, the "for/else" proposal, and other posts already discussed, shows that something should be done to improve the break situation.
Personally I like the break2, break3 solution, and I do not dislike the "for/else" either because it allows to do connect another break when inner loop break is detected, with an extra line but with no need of extra condition or goto.
Also the "for/else" allows the detection when a loop has ended normally or has been "aborted" which is nice to know aswell.
So I hope something can be done in a future.


That's all. Thank you for the feedback.

Nicol Bolas

unread,
Sep 8, 2016, 11:46:03 PM9/8/16
to ISO C++ Standard - Future Proposals, amg...@gmail.com
On Thursday, September 8, 2016 at 2:25:11 PM UTC-4, amg...@gmail.com wrote:
Finding a `goto` label is done via a simple string search. A good IDE can give it to you by simply right-clicking and picking a menu-item, or with a keyboard shortcut. Finding where `break 2` goes require finding the two nearest loops, which may be off-screen.

Well, this is going to a too much more complicated issue that it started. If you see my initial example, it is very simple, you do not need a 3 page code to make use of it. What I mean is, if the code containing the inner loops is complex enough you should split that code into another method containing the loops, and this way you solve both: the break will be replaced by a return, and the complexity of the method will decrease by splling it.

But, as my example, if code is small enough due to inner code loops are simple, you want a clean and fast exit. Splitting the method is discarded in this case, so you only can use the goto or adding extra conditions.

So, we restricting the use of this feature to times when you have multiple loops, but they're small enough to fit on one screen. If that's the case, then a `goto` is just as good as `break(X)`. In both cases, you can see on one screen exactly where you will go.

So even in the best possible scenario, your `break(X)` isn't better than a `goto`. Your primary argument seems to be one of taste, of simply preferring `break` over `goto`.

Oh, and there's another thing that makes your idea problematic. It doesn't combine well with the proposal for a "for/else" mechanism. What would happen if you use `break(2)` and the inner loop has an `else` clause (or whatever we want to call it)? By limiting `break` to just one loop, we ensure that such a proposal still makes sense.


I didn't know that proposal, but looks already incompatible by using goto inside isn't? My proposal isn't incompatible with anything because internally it can be translated to a goto by the compiler.

`goto` is incompatible with that, of course. But it's not supposed to be compatible with it. Using it bypasses control flow; that's the point.

By contrast, the use of the `break` keyword is supposed to trigger the else/catch break/whatever clause. So if you use a multi-level break, but the inner loop that has an else/catch break/whatever clause... how does that work? Do you execute the else block or not? If you do, then what happens at the end of the block? If you don't execute the block, then that would seem to obviate the whole point of the for/else construct, which explicitly allows you to catch break instructions and handle them.

FrankHB1989

unread,
Sep 9, 2016, 12:09:43 AM9/9/16
to ISO C++ Standard - Future Proposals, amg...@gmail.com


在 2016年9月9日星期五 UTC+8上午1:39:39,Nicol Bolas写道:
It sounds like we'd better have more powerful control primitives (e.g. delimited continuations) so all these proposals can be implemented as library features... with less disputations, probably.

It would also be interesting to replace all current control keywords (including `return` and `try`/`catch`) with simpler (in sense of specification) primitives portably.


Hyman Rosen

unread,
Sep 9, 2016, 9:09:53 AM9/9/16
to std-pr...@isocpp.org
Given my endless arguing in the order-of-evaluation threads, I have really come to hate the "promotes bad code" arguments.  The proof that break Label; is good is that Ada has it.  And by the way, have none of the "bad code" arguers ever had to exit a for loop from inside a switch statement?

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.

To post to this group, send email to std-pr...@isocpp.org.

Ville Voutilainen

unread,
Sep 9, 2016, 9:55:43 AM9/9/16
to ISO C++ Standard - Future Proposals
On 9 September 2016 at 16:09, Hyman Rosen <hyman...@gmail.com> wrote:
> Given my endless arguing in the order-of-evaluation threads, I have really
> come to hate the "promotes bad code" arguments. The proof that break Label;
> is good is that Ada has it. And by the way, have none of the "bad code"
> arguers ever had to exit a for loop from inside a switch statement?


Not after writing the code to be less bad, i.e. not to contain a for
loop inside a switch statement.
I tend not to nest loops, and especially not to nest loops under
selection statements.

Ville Voutilainen

unread,
Sep 9, 2016, 9:56:43 AM9/9/16
to ISO C++ Standard - Future Proposals
On 9 September 2016 at 16:55, Ville Voutilainen
Also, your very nice "proof" from Ada is nullified by Java also having
a break Label, which means
that it can't be good. Your move.

Greg Marr

unread,
Sep 9, 2016, 10:13:21 AM9/9/16
to ISO C++ Standard - Future Proposals
I believe you read that backwards.  The switch is inside the for.

Ville Voutilainen

unread,
Sep 9, 2016, 10:20:57 AM9/9/16
to ISO C++ Standard - Future Proposals
Good catch. I don't recall doing that all that often either, except
when the return mechanism
used is a) a return b) an exception.

Tony V E

unread,
Sep 9, 2016, 10:30:09 AM9/9/16
to Standard Proposals
I think it is the opposite - the switch is inside the for-loop.  Thus you can't use 'break' to break from the for-loop.

FWIW.
 

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.

Peter Koch Larsen

unread,
Sep 9, 2016, 4:45:55 PM9/9/16
to ISO C++ Standard - Future Proposals


Den fredag den 9. september 2016 kl. 15.09.53 UTC+2 skrev Hyman Rosen:
Given my endless arguing in the order-of-evaluation threads, I have really come to hate the "promotes bad code" arguments.  The proof that break Label; is good is that Ada has it.  And by the way, have none of the "bad code" arguers ever had to exit a for loop from inside a switch statement?

No, I have never had to do that. It would be nice to see actual code written in modern C++ demonstrating the problem. Perhaps good examples can be found on Github?
By the way, I do not buy the argument that everything in the Ada standard is good.

/Peter

Nicol Bolas

unread,
Sep 11, 2016, 12:56:41 PM9/11/16
to ISO C++ Standard - Future Proposals, amg...@gmail.com, szollos...@gmail.com
On Thursday, September 8, 2016 at 2:26:19 PM UTC-4, szollos...@gmail.com wrote:
Hi,

Note that this is essentially solved by the idea of 'capturing monads in lambdas'.

Now that I have a better grasp of that idea, I fail to see how your version constitutes a superior version of the feature, relative to a `goto`. Consider the example you posted there:

for (auto&& person : people)
{
   
auto break_twice = [&break]{ break; }
   
for (auto&& phone : person.phones)
   
{
       
if (isLandline(phone))
       
{
            std
::cout << person.name << " " << phone
                     
<< " still uses landline, do not switch it off!"
                     
<< std::endl;
            break_twice
();
       
}
   
}
}

As I understand your feature, that is not a "break twice". The `break` will happen relative to the level where the lambda was defined. That is, it will break from out of the first loop. It doesn't break twice from wherever you happen to be when you call it. It breaks out of the loop in which the lambda was defined.

That's very different from `break(2)`, which always goes back 2 levels.

If that weren't the case, if calling the function executed a `break` that was relative to the call site... then it would be no different than just typing `break`, right? So it has to work relative to where it is defined.

The labeled `goto` case works essentially the same way:

for (auto&& person : people)
{
   
for (auto&& phone : person.phones)
   
{
       
if (isLandline(phone))
       
{
            std
::cout << person.name << " " << phone
                     
<< " still uses landline, do not switch it off!"
                     
<< std::endl;
           
goto break_twice;
       
}
   
}
} break_twice:

In both cases, you are always breaking out of the outer loop, no matter how many loops are in the way. Both cases require explicitly marking, not the number of loops to exit, but the location you're exiting to.

So what's the difference?

Hyman Rosen

unread,
Sep 12, 2016, 7:00:03 PM9/12/16
to std-pr...@isocpp.org, amg...@gmail.com, szollos...@gmail.com
And the labeled break is superior to both:

outer: for (auto&& person : people{
    inner: 
for (auto&& phone : person.phones{

        
if (isLandline(phone)) {
            std
::cout << person.name << " " << phone
                      
<< " still uses landline, do not switch it off!"
                      
<< std::endl;

            
break outer;
        
}
    
}
}

The label is seen before the statement that uses it, and break and continue statements are already "grokked" by programmers of C-derived languages.  That means readers of the code don't have to worry about where a goto is going.  That's why they invented structured programming, after all.

amg...@gmail.com

unread,
Sep 14, 2016, 11:37:12 AM9/14/16
to ISO C++ Standard - Future Proposals, amg...@gmail.com, szollos...@gmail.com
while ( there are ppl wants to complicate things )
{
     while( they want to define labels and write more than necessary )
     {
 break2; // make your life simpler

Ren Industries

unread,
Sep 14, 2016, 12:14:25 PM9/14/16
to std-pr...@isocpp.org
break2 does not make anyones life easier except in very trivial cases. In larger cases, it causes much more "spooky action at a distance" than labels, which are much neater, cleaner, and more explicit.


--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.

Victor Dyachenko

unread,
Sep 15, 2016, 3:40:12 AM9/15/16
to ISO C++ Standard - Future Proposals, amg...@gmail.com
Good idea. This makes break usable in code like this:

for(;;)
{
   
switch(...)
   
{
       
case ...:
           
break(2); // exit the for loop
   
}
}



D. B.

unread,
Sep 15, 2016, 4:49:03 AM9/15/16
to std-pr...@isocpp.org
The point is that it makes it "usable" but unnecessarily arcane and not conducive to deeper loops - where the latter are presumably why people think they want this in the first place. Sure, they could have it, and then they'd have to mentally track how many loops they were currently in. Is that really a benefit?

My vote still goes to the much-maligned goto, which gets excessive flak because the community thinks (probably mostly in their imagination) that noobs are going to do horrible things with it, but it exists precisely for the rest of us to do stuff like this:

for(;;)
{
   
switch(...)
   
{
       
case ...:

            goto out_of_for
; // exit the for loop
   
}
}

out_of_for:

Message has been deleted

Carl Cook

unread,
Sep 15, 2016, 7:40:27 AM9/15/16
to ISO C++ Standard - Future Proposals

As a side note, what about a "block" statement? I'd find this useful. It's basically a more concise mechanism than do {} while (false);


E.g.


block 
{
  
DoSomethingUseful();
  
if (x == 0)
    break;
  
DoSomethingElse();
  
if (== 0)
    
break;
  DoAnotherThing();

}

This way you don't end up with deeply nested if-then-else blocks. It's fairly similar to a goto, but without actually being one ;)

Has this been proposed before?

Cheers,
Carl

Victor Dyachenko

unread,
Sep 15, 2016, 7:44:28 AM9/15/16
to ISO C++ Standard - Future Proposals
Why not just

{
 
DoSomethingUseful();
 
if (x == 0)
   
break;
 
DoSomethingElse();
 
if (y == 0)
   
break;
 
DoAnotherThing();
}

I think additional keyword is redundant here.

Carl Cook

unread,
Sep 15, 2016, 7:50:02 AM9/15/16
to std-pr...@isocpp.org
Break statements need to be within a loop or switch, right?


--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.

Victor Dyachenko

unread,
Sep 15, 2016, 7:54:35 AM9/15/16
to ISO C++ Standard - Future Proposals
On Thursday, September 15, 2016 at 2:50:02 PM UTC+3, Carl Cook wrote:
Break statements need to be within a loop or switch, right?

Yes, but you are trying to propose new feature. Aren't you?

Carl Cook

unread,
Sep 15, 2016, 7:57:34 AM9/15/16
to std-pr...@isocpp.org
Break statements need to be within a loop or switch, right?

Yes, but you are trying to propose new feature. Aren't you?

Only if it's a good idea.

I see what you are saying now... indeed the "block" statement is redundant, and such a feature would not introduce any breaking changes (pun intended).

Victor Dyachenko

unread,
Sep 15, 2016, 8:03:19 AM9/15/16
to ISO C++ Standard - Future Proposals
On Thursday, September 15, 2016 at 2:57:34 PM UTC+3, Carl Cook wrote:

I see what you are saying now... indeed the "block" statement is redundant, and such a feature would not introduce any breaking changes (pun intended).

Exactly. I find it useful feature - exit from the current block or loop (which body may not be a block, just one expression statement).

Alexey Mamontov

unread,
Sep 15, 2016, 8:26:01 AM9/15/16
to ISO C++ Standard - Future Proposals, amg...@gmail.com

 
while ( cond1 )
 
{
       
while ( cond2 )
       
{
           
if ( cond3 )
           
{

               
break, break;
           
}
           
else if ( cond4)
           
{
               
break, continue;
            }
       
}
       
// code reached only if !cond2
 
}


Why is it good:
* We use the comma operator in its intuitive manner
* IDE can highlight related keywords
* It doesn't make it comfortable to create many embedded loops
* Allows to continue as the last operation (nice bonus)

Moritz Klammler

unread,
Sep 15, 2016, 12:59:23 PM9/15/16
to std-pr...@isocpp.org
Victor Dyachenko <victor.d...@gmail.com> writes:

> Why not just
> {
> DoSomethingUseful();
> if (x == 0)
> break;
> DoSomethingElse();
> if (y == 0)
> break;
> DoAnotherThing();
> }
>
> I think additional keyword is redundant here.

I don't think that this is going to work.

Consider the following code, which is valid and obvious in every version
of C++.

while (more_stuff_to_do())
{
if (tired_of_doing_stuff())
{
if (boss_is_not_here())
break; // Where should control flow be transferred?
std::cout << "Okay, I'll keep going...\n";
}
}

And even if you invent a (presumably not very intuitive) rule for how
this case would be handled, you would still break *lots* of existing
code like this.

while (true)
{
std::unique_ptr<thing> mything{};
// Nested scope is used because of the RAII lock.
{
std::lock_guard lg{mymutex};
if (queue.empty())
break; // Intention is to break out of the while loop.
mything = queue.pop();
}
// Work with my thing...
}

D. B.

unread,
Sep 15, 2016, 1:10:53 PM9/15/16
to std-pr...@isocpp.org

On Thu, Sep 15, 2016 at 1:26 PM, Alexey Mamontov <cara...@gmail.com> wrote:

 
while ( cond1 )
 
{
       
while ( cond2 )
       
{
           
if ( cond3 )
           
{

               
break, break;
           
}
           
else if ( cond4)
           
{
               
break, continue;
            }
       
}
       
// code reached only if !cond2
 
}


Why is it good:
* We use the comma operator in its intuitive manner

I don't have anything fundamentally against this syntax, but I wouldn't say it's intuitive/familiar, since it introduces yet another new overload for the comma.

 
* It doesn't make it comfortable to create many embedded loops
* Allows to continue as the last operation (nice bonus)

These are indeed benefits, if we 'must' have any feature like this - especially the one that discourages it ;-)
 

Magnus Fromreide

unread,
Sep 15, 2016, 1:18:07 PM9/15/16
to std-pr...@isocpp.org, amg...@gmail.com
Is this general statement stacking?

Should

break, throw x;

mean that you should leave the innermost loop and then throw?

Should

return 17, break;

mean 'Return from this function and break out of the current loop or switch
in the calling function'?

/MF

Victor Dyachenko

unread,
Sep 16, 2016, 2:52:30 AM9/16/16
to ISO C++ Standard - Future Proposals
On Thursday, September 15, 2016 at 7:59:23 PM UTC+3, Moritz Klammler wrote:
I don't think that this is going to work.

Consider the following code, which is valid and obvious in every version
of C++.

    while (more_stuff_to_do())
      {
        if (tired_of_doing_stuff())
          {
            if (boss_is_not_here())
              break;  // Where should control flow be transferred?
            std::cout << "Okay, I'll keep going...\n";
          }
      }

And even if you invent a (presumably not very intuitive) rule for how
this case would be handled, you would still break *lots* of existing
code like this.

On Thursday, September 15, 2016 at 3:03:19 PM UTC+3, Victor Dyachenko wrote:
exit from the current block or loop (which body may not be a block, just one expression statement).
 
    while (true)
      {
        std::unique_ptr<thing> mything{};
        // Nested scope is used because of the RAII lock.
        {
          std::lock_guard lg{mymutex};
          if (queue.empty())
            break;  // Intention is to break out of the while loop.
          mything = queue.pop();
        }
        // Work with my thing...
      }
Yes, this case is broken... :-(

michael...@googlemail.com

unread,
Sep 16, 2016, 5:40:35 AM9/16/16
to ISO C++ Standard - Future Proposals, amg...@gmail.com, szollos...@gmail.com


On Wednesday, September 14, 2016 at 4:37:12 PM UTC+1, amg...@gmail.com wrote:
while ( there are ppl wants to complicate things )
{
     while( they want to define labels and write more than necessary )
     {
 break2; // make your life simpler
     }
}

With regards to your solution 1 in the original OP of using a function and then calling return. You say it is elegant but slow. Because of the time you need to take to create a function? If that is such an issue why not just do an immediately invoked lambda expression which was one of Jason Turner's key points at boostcon:

[&](){
  while ( cond1 )
        {
            while ( cond2 )
            {
                if ( cond3 )
                {

      return;
                }
            }           
        }
}();

Really though, if you're going to have such complexity within your program, with it to be iterating through several loops, it would be better for you to separate it out into its own method or function function and give it a meaningful name. I've seen many talks from the likes of Herb Sutter, Sean Parent and Bjarne Stroustrup on the subject of reducing the complexity of your code and making it intuitive to read by dividing up the problem and giving each area of the code its own name. For these reasons, while I do see why you want break(n), solution 1 is probably the most acceptable way to handle this issue. Regardless of the extra time incurred in creating the new method/function. And

Matthew Woehlke

unread,
Sep 17, 2016, 11:12:10 AM9/17/16
to std-pr...@isocpp.org
On 2016-09-15 07:40, Carl Cook wrote:
> As a side note, what about a "block" statement? I'd find this useful. It's
> basically a more concise mechanism than do {} while (false);
>
> E.g.
>
> block
> {
> DoSomethingUseful();
> if (x == 0)
> break;
> DoSomethingElse();
> if (y == 0)
> break;
> DoAnotherThing();
> }

#define block for(int _block ## __LINE__ = 0; \
_block ## __LINE__ = 0; \
++_block ## __LINE__)

...or use `do { ... } while(0)`.

--
Matthew

Ville Voutilainen

unread,
Sep 17, 2016, 11:42:38 AM9/17/16
to ISO C++ Standard - Future Proposals
We already have a mechanism for things like that, and it doesn't
require any macros.
You replace 'block' with '[&]', 'break' with 'return' and add a '();'
at the end.

[&]
{
DoSomethingUseful();
if (x==0)
return;
DoSomethingElse();
if (y == 0)
return;
DoAnotherThing();
}();

Matthew Woehlke

unread,
Sep 21, 2016, 12:06:16 PM9/21/16
to std-pr...@isocpp.org
On 2016-09-17 11:42, Ville Voutilainen wrote:
> On 16 September 2016 at 18:06, Matthew Woehlke wrote:
>> On 2016-09-15 07:40, Carl Cook wrote:
>>> As a side note, what about a "block" statement? I'd find this useful. It's
>>> basically a more concise mechanism than do {} while (false);
>>>
>>> E.g.
>>>
>>> block
>>> {
>>> DoSomethingUseful();
>>> if (x == 0)
>>> break;
>>> DoSomethingElse();
>>> if (y == 0)
>>> break;
>>> DoAnotherThing();
>>> }
>>
>> #define block for(int _block ## __LINE__ = 0; \
>> _block ## __LINE__ = 0; \
>> ++_block ## __LINE__)
>>
>> ...or use `do { ... } while(0)`.
>
> We already have a mechanism for things like that, and it doesn't
> require any macros.
> You replace 'block' with '[&]', 'break' with 'return' and add a '();'
> at the end.

Okay, so there are (at least) *three* ways to achieve what Carl proposed
:-). (The macro happens to produce the exact syntax he showed, although
I'd personally prefer the do...while. I don't see how a lambda is an
improvement; if nothing else, you can't actually `return` from it.)

--
Matthew

Reply all
Reply to author
Forward
0 new messages