Interest in breakable labeled scope emulation?

Hi all, One of the few things I appreciate in Java is the labeled-break feature. I think C++ would provide it as well in future standard but it seems that there's no even such a proposal. In lack of the language feature, a simple emulation can be used: --------------------------------------------------- #define BOOST_SCOPE(name) \ if (const bool LABELED_SCOPE_##name = false){break(name); name:;} else #define break(name) \ (void)LABELED_SCOPE_##name; goto name; --------------------------------------------------- Now we can write: BOOST_SCOPE(a) { break(a); cout << "123\n"; } The real world usage would reside in nested loop&switch where labeled-break really shines. Thoughts? Sorry if this idea is too simple and somewhat rejected before...

break is a standard c++ keyword already. Also I don't understand what problem this solve. Joel Lamotte

Le 13/01/13 17:13, Klaim - Joël Lamotte a écrit :
break is a standard c++ keyword already. Yes, BOOST_BREAK should be used instead
Also I don't understand what problem this solve.
Exiting from nested loops is something that could be quite complex using structured programming. Named blocks try to make more structured a goto based solution, by allowing only to restart/leave a block from inside it. BOOST_NAMED_BLOCK(L) for(;;) { while (cnd) { if (cnd2) BOOST_BREAK(L); // go to [1] } } // [1] Of course in order to be really structired the jumping to the underlying label should be forbiden (by the compiler), but I don't think that a preprocessor solution could take care of this. So the following not desired and not structured code could compile even if we would like an compile error. BOOST_NAMED_BLOCK(L) { // ... } // [1] //... BOOST_BREAK(L); // go to [1] HTH, Vicente

Den Sun, 13 Jan 2013 20:30:14 +0100 skrev Vicente J. Botet Escriba <vicente.botet@wanadoo.fr>: [snip]
Of course in order to be really structired the jumping to the underlying label should be forbiden (by the compiler), but I don't think that a preprocessor solution could take care of this. So the following not desired and not structured code could compile even if we would like an compile error.
BOOST_NAMED_BLOCK(L) { // ... } // [1] //... BOOST_BREAK(L); // go to [1]
So, the underlying idea is to get something like "break" and "continue" to work inside any "named" block, not just loops? If so (as you demonstrate above) I'm fairly certain a correct solution cannot be implemented using just the preprocessor. /Brian

Le 13/01/13 20:37, Brian Ravnsgaard Riis a écrit :
Den Sun, 13 Jan 2013 20:30:14 +0100 skrev Vicente J. Botet Escriba <vicente.botet@wanadoo.fr>:
[snip]
Of course in order to be really structured the jumping to the underlying label should be forbiden (by the compiler), but I don't think that a preprocessor solution could take care of this. So the following not desired and not structured code could compile even if we would like an compile error.
BOOST_NAMED_BLOCK(L) { // ... } // [1] //... BOOST_BREAK(L); // go to [1]
So, the underlying idea is to get something like "break" and "continue" to work inside any "named" block, not just loops? If so (as you demonstrate above) I'm fairly certain a correct solution cannot be implemented using just the preprocessor. I believe preprocesor can provide a solution that allows you write correct programs but don't avoid bad uses. Even in this case, exiting from nested loops could be more easy to write/read as showed here.
BOOST_NAMED_BLOCK(L) for(;;) { while (cnd) { if (cnd2) BOOST_BREAK(L); // go to [1] } } // [1] Well this is always subjective ;-) Best, Vicente

2013/1/14 Brian Ravnsgaard Riis <brian@ravnsgaard.net>
Den Sun, 13 Jan 2013 20:30:14 +0100 skrev Vicente J. Botet Escriba < vicente.botet@wanadoo.fr>:
[snip]
Of course in order to be really structired the jumping to the underlying
label should be forbiden (by the compiler), but I don't think that a preprocessor solution could take care of this. So the following not desired and not structured code could compile even if we would like an compile error.
BOOST_NAMED_BLOCK(L) { // ... } // [1] //... BOOST_BREAK(L); // go to [1]
So, the underlying idea is to get something like "break" and "continue" to work inside any "named" block, not just loops? If so (as you demonstrate above) I'm fairly certain a correct solution cannot be implemented using just the preprocessor.
Hey guys, Please try the code attached and see the error message that your compiler gives. It DOES avoid the ill-formed code like that to compile. And thanks Vicente for the elaboration.

Le 14/01/13 02:50, TONGARI a écrit :
2013/1/14 Brian Ravnsgaard Riis <brian@ravnsgaard.net>
Den Sun, 13 Jan 2013 20:30:14 +0100 skrev Vicente J. Botet Escriba < vicente.botet@wanadoo.fr>:
[snip]
Of course in order to be really structired the jumping to the underlying
label should be forbiden (by the compiler), but I don't think that a preprocessor solution could take care of this. So the following not desired and not structured code could compile even if we would like an compile error.
BOOST_NAMED_BLOCK(L) { // ... } // [1] //... BOOST_BREAK(L); // go to [1]
So, the underlying idea is to get something like "break" and "continue" to work inside any "named" block, not just loops? If so (as you demonstrate above) I'm fairly certain a correct solution cannot be implemented using just the preprocessor.
Hey guys,
Please try the code attached and see the error message that your compiler gives. It DOES avoid the ill-formed code like that to compile.
Yeah. I was your macro forbid the access from outside the block. I though that the trick was used only to be able to add a label at the end of the block. But the use of the variable on the BREAK macro make it fail. Really clever. #define BOOST_SCOPE(name) \ if (const bool LABELED_SCOPE_##name = false){BOOST_BREAK(name); name##_end_scope:;} else #define BOOST_BREAK(name) \ (void)LABELED_SCOPE_##name; goto name##_end_scope I have tried int main() { BOOST_SCOPE(a2) { BOOST_BREAK(a2); cout << "123\n"; } BOOST_SCOPE(a1) { BOOST_BREAK(a2); cout << "123\n"; } return 0; } and here are the error for gcc darwin.compile.c++ ../../../bin.v2/libs/thread/test/test_so.test/darwin-4.7.2x/debug/threading-multi/test_so.o ../example/test_so.cpp: In function ‘int main()’: ../example/test_so.cpp:22:1: erreur: ‘LABELED_SCOPE_a2’ was not declared in this scope ../example/test_so.cpp:15:1: attention : jump to label ‘a2_end_scope’ [-fpermissive] ../example/test_so.cpp:22:1: attention : à partir d'ici [-fpermissive] ../example/test_so.cpp:15:1: erreur: skips initialization of ‘const bool LABELED_SCOPE_a2’ and clang clang-darwin.compile.c++ ../../../bin.v2/libs/thread/test/test_so.test/clang-darwin-3.2xl/debug/threading-multi/test_so.o ../example/test_so.cpp:22:7: error: use of undeclared identifier 'LABELED_SCOPE_a2' BOOST_BREAK(a2); ^ ../example/test_so.cpp:10:7: note: expanded from macro 'BOOST_BREAK' (void)LABELED_SCOPE_##name; goto name##_end_scope ^ <scratch space>:232:1: note: expanded from macro 'LABELED_SCOPE_' LABELED_SCOPE_a2 ^ Best, Vicente

2013/1/14 Vicente J. Botet Escriba <vicente.botet@wanadoo.fr>
Yeah. I was your macro forbid the access from outside the block. I though that the trick was used only to be able to add a label at the end of the block. But the use of the variable on the BREAK macro make it fail. Really clever.
#define BOOST_SCOPE(name) \ if (const bool LABELED_SCOPE_##name = false){BOOST_BREAK(name); name##_end_scope:;} else
#define BOOST_BREAK(name) \ (void)LABELED_SCOPE_##name; goto name##_end_scope
Modification: #define BOOST_BREAK(name) \ do {goto name##_end_scope;} while (LABELED_SCOPE_##name) This makes it a single stmt and the below should work: if (...) BOOST_BREAK(...);

On Sun, Jan 13, 2013 at 8:30 PM, Vicente J. Botet Escriba < vicente.botet@wanadoo.fr> wrote:
Exiting from nested loops is something that could be quite complex using structured programming.
Named blocks try to make more structured a goto based solution, by allowing only to restart/leave a block from inside it.
BOOST_NAMED_BLOCK(L) for(;;) { while (cnd) {
if (cnd2) BOOST_BREAK(L); // go to [1] } } // [1]
Of course in order to be really structired the jumping to the underlying label should be forbiden (by the compiler), but I don't think that a preprocessor solution could take care of this. So the following not desired and not structured code could compile even if we would like an compile error.
Ok but then what's the difference with goto and a label? Doesn't it already work like that in C++? Sorry if it should be obvious... Joel Lamotte

Le 14/01/13 00:51, Klaim - Joël Lamotte a écrit :
On Sun, Jan 13, 2013 at 8:30 PM, Vicente J. Botet Escriba < vicente.botet@wanadoo.fr> wrote:
Exiting from nested loops is something that could be quite complex using structured programming.
Named blocks try to make more structured a goto based solution, by allowing only to restart/leave a block from inside it.
BOOST_NAMED_BLOCK(L) for(;;) { while (cnd) {
if (cnd2) BOOST_BREAK(L); // go to [1] } } // [1]
Of course in order to be really structired the jumping to the underlying label should be forbiden (by the compiler), but I don't think that a preprocessor solution could take care of this. So the following not desired and not structured code could compile even if we would like an compile error.
Ok but then what's the difference with goto and a label? Doesn't it already work like that in C++? Sorry if it should be obvious...
Yes. The single difference would be where the label appear on the code and which instruction do you use to exit from the loop and that the direct use of label/goto is not telling me "please don't use direct goto to this label, it is intended to be used only inside this block". Even if the preprocessor don't help here, an offline tool could use this information to report a warning. for(;;) { while (cnd) { if (cnd2) goto L; // [2] } } L:; // [1] Anyway, it would be great if the C++ language supports this kind of more structured jumps, but I can leave without. Best, Vicente

Le 13/01/13 13:30, TONGARI a écrit :
Hi all,
One of the few things I appreciate in Java is the labeled-break feature. I think C++ would provide it as well in future standard but it seems that there's no even such a proposal.
In lack of the language feature, a simple emulation can be used:
--------------------------------------------------- #define BOOST_SCOPE(name) \ if (const bool LABELED_SCOPE_##name = false){break(name); name:;} else
#define break(name) \ (void)LABELED_SCOPE_##name; goto name; --------------------------------------------------- Now we can write:
BOOST_SCOPE(a) { break(a); cout << "123\n"; }
The real world usage would reside in nested loop&switch where labeled-break really shines.
Thoughts? Sorry if this idea is too simple and somewhat rejected before...
Beta language provides restart and leave a named blocks which are a little bit more structured than gotos. L:: { restart L; leave L; } which in C/C++ could be implemented as restart_L: { //restart L; goto restart_L; //leave L; goto leave_L; } leave_L; Maybe adapting your macros both can be provided #define BOOST_RESTART(name) \ goto BOOST_NAMED_BLOCK_RESTART_##name #define BOOST_LEAVE(name) \ goto BOOST_NAMED_BLOCK_LEAVE_##name #define BOOST_NAMED_BLOCK(name) \ BOOST_NAMED_BLOCK_RESTART_##name: \ if (const bool BOOST_NAMED_BLOCK_##name = false){ (void)BOOST_NAMED_BLOCK_##name; BOOST_NAMED_BLOCK_LEAVE_##name:;} else With these macros we can be able to do the following BOOST_NAMED_BLOCK(L) { BOOST_RESTART(L); BOOST_LEAVE(L); } The problem is that BOOST_NAMED_BLOCK(L) is not an statement but two. Maybe you see a way to workaround this limitation. I don't know however if the name LEAVE is a better name on the c++ context. Best, Vicente

On Jan 13, 2013, at 7:30 AM, TONGARI <tongari95@gmail.com> wrote:
One of the few things I appreciate in Java is the labeled-break feature. I think C++ would provide it as well in future standard but it seems that there's no even such a proposal.
In lack of the language feature, a simple emulation can be used:
--------------------------------------------------- #define BOOST_SCOPE(name) \ if (const bool LABELED_SCOPE_##name = false){break(name); name:;} else
#define break(name) \ (void)LABELED_SCOPE_##name; goto name; --------------------------------------------------- Now we can write:
BOOST_SCOPE(a) { break(a); cout << "123\n"; }
The real world usage would reside in nested loop&switch where labeled-break really shines.
While I understand the value of being able to exit such compound scopes cleanly, goto is a poor solution as it bypasses destructors, which makes this idea error prone. ___ Rob

2013/1/14 Rob Stewart <robertstewart@comcast.net>
On Jan 13, 2013, at 7:30 AM, TONGARI <tongari95@gmail.com> wrote:
One of the few things I appreciate in Java is the labeled-break feature. I think C++ would provide it as well in future standard but it seems that there's no even such a proposal.
In lack of the language feature, a simple emulation can be used:
--------------------------------------------------- #define BOOST_SCOPE(name) \ if (const bool LABELED_SCOPE_##name = false){break(name); name:;} else
#define break(name) \ (void)LABELED_SCOPE_##name; goto name; --------------------------------------------------- Now we can write:
BOOST_SCOPE(a) { break(a); cout << "123\n"; }
The real world usage would reside in nested loop&switch where labeled-break really shines.
While I understand the value of being able to exit such compound scopes cleanly, goto is a poor solution as it bypasses destructors, which makes this idea error prone.
No. At least for g++ & clang that I tested the stack is correctly unwound and the dtors are called.

2013/1/14 TONGARI <tongari95@gmail.com>
2013/1/14 Rob Stewart <robertstewart@comcast.net>
On Jan 13, 2013, at 7:30 AM, TONGARI <tongari95@gmail.com> wrote:
One of the few things I appreciate in Java is the labeled-break feature. I think C++ would provide it as well in future standard but it seems that there's no even such a proposal.
In lack of the language feature, a simple emulation can be used:
--------------------------------------------------- #define BOOST_SCOPE(name) \ if (const bool LABELED_SCOPE_##name = false){break(name); name:;} else
#define break(name) \ (void)LABELED_SCOPE_##name; goto name; --------------------------------------------------- Now we can write:
BOOST_SCOPE(a) { break(a); cout << "123\n"; }
The real world usage would reside in nested loop&switch where labeled-break really shines.
While I understand the value of being able to exit such compound scopes cleanly, goto is a poor solution as it bypasses destructors, which makes this idea error prone.
No. At least for g++ & clang that I tested the stack is correctly unwound and the dtors are called.
You may want to see 6.7/3 "Declaration statement". It's standard guaranteed.

On Jan 14, 2013, at 7:49 AM, TONGARI <tongari95@gmail.com> wrote:
2013/1/14 TONGARI <tongari95@gmail.com>
2013/1/14 Rob Stewart <robertstewart@comcast.net>
While I understand the value of being able to exit such compound scopes cleanly, goto is a poor solution as it bypasses destructors, which makes this idea error prone.
No. At least for g++ & clang that I tested the stack is correctly unwound and the dtors are called.
You may want to see 6.7/3 "Declaration statement". It's standard guaranteed.
Quite right. I was thinking of sethmp/longjmp when I wrote that. Sorry for the noise. ___ Rob

On 14 January 2013 10:56 Rob Stewart [mailto:robertstewart@comcast.net] wrote :-
While I understand the value of being able to exit such compound scopes cleanly, goto is a poor solution as it bypasses destructors, which makes this idea error prone.
Really? - that's rather worrying - especially for RAII idiom I don't use goto very often but I know it exists at various points in our code base (+ lots of RAII classes) was under the impression that destructors were handled correctly with goto - am I wrong? I just tried :- #include <iostream> struct A { ~A() {std::cout << "destructor called\n"; } }; int main( int argc, char** argv ) { std::cout << "start 1st scope\n"; { A a; } std::cout << "end 1st scope\n"; std::cout << "start 2nd scope\n"; { A a; goto end_scope2; } end_scope2: std::cout << "end 2nd scope\n"; std::cout << "start 3rd scope\n"; if ( false ) { end_scope3:; } else { A a; goto end_scope3; } std::cout << "end 3rd scope\n"; return 0; } And got start 1st scope destructor called end 1st scope start 2nd scope destructor called end 2nd scope start 3rd scope destructor called end 3rd scope for (Windows 7) C:\Workspace\test>cl --version Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. And (Centos 6) []$ g++ --version g++ (GCC) 4.4.6 20120305 (Red Hat 4.4.6-4) So seems to call the destructor in the correct place. Alex

On 14 January 2013 13:06 Alex Perry wrote :-
I don't use goto very often but I know it exists at various points in our code base (+ lots of RAII classes) was under the impression that destructors were handled correctly with goto - am I wrong?
Sorry for noise - should have googled rather than replied but it worried me [1] [1] http://stackoverflow.com/questions/3179936/goto-out-of-a-block-do-destructor...

On Sun, Jan 13, 2013 at 4:30 AM, TONGARI <tongari95@gmail.com> wrote:
Hi all,
One of the few things I appreciate in Java is the labeled-break feature. I think C++ would provide it as well in future standard but it seems that there's no even such a proposal.
In lack of the language feature, a simple emulation can be used:
--------------------------------------------------- #define BOOST_SCOPE(name) \ if (const bool LABELED_SCOPE_##name = false){break(name); name:;} else
#define break(name) \ (void)LABELED_SCOPE_##name; goto name; --------------------------------------------------- Now we can write:
BOOST_SCOPE(a) { break(a); cout << "123\n"; }
The real world usage would reside in nested loop&switch where labeled-break really shines.
Thoughts? Sorry if this idea is too simple and somewhat rejected before...
It's a nice thought but: (a) I think the situation where you want to break and/or continue more than one loop-level out at a time is rare; and (b) in those rare situations, explicitly using gotos and labels (with a descriptive name) is reasonably brief and readable; so I would be hesitant to adopt this. - Jeff

2013/1/16 Jeffrey Lee Hellrung, Jr. <jeffrey.hellrung@gmail.com>
It's a nice thought but: (a) I think the situation where you want to break and/or continue more than one loop-level out at a time is rare; and (b) in those rare situations, explicitly using gotos and labels (with a descriptive name) is reasonably brief and readable; so I would be hesitant to adopt this.
Why not provide a more structured way for jumping if we really want to deprecate 'goto' in C++? It's not only for the old hands but the newcomers to adopt a more expressive control style. I think Boost is a good place to start with, and we'll see if it'd be finally made into C++ language.

On Tue, Jan 15, 2013 at 6:10 PM, TONGARI <tongari95@gmail.com> wrote:
2013/1/16 Jeffrey Lee Hellrung, Jr. <jeffrey.hellrung@gmail.com>
It's a nice thought but: (a) I think the situation where you want to break and/or continue more
than
one loop-level out at a time is rare; and (b) in those rare situations, explicitly using gotos and labels (with a descriptive name) is reasonably brief and readable; so I would be hesitant to adopt this.
Why not provide a more structured way for jumping if we really want to deprecate 'goto' in C++? It's not only for the old hands but the newcomers to adopt a more expressive control style.
I think Boost is a good place to start with, and we'll see if it'd be finally made into C++ language.
I would be supportive in considering adding syntactic support for "break LABEL" and "continue LABEL", but we have already have a reasonably good emulation that's entirely transparent (meaning, not hidden behind macros): {for(...) { for(...) { if(...) goto BREAK_FOR; } }BREAK_FOR:;} for(...) {{ for(...) { if(...) goto CONTINUE_FOR; } }CONTINUE_FOR:;} - Jeff

Le 15/01/13 18:44, Jeffrey Lee Hellrung, Jr. a écrit :
On Sun, Jan 13, 2013 at 4:30 AM, TONGARI <tongari95@gmail.com> wrote:
Hi all,
One of the few things I appreciate in Java is the labeled-break feature. I think C++ would provide it as well in future standard but it seems that there's no even such a proposal.
In lack of the language feature, a simple emulation can be used:
--------------------------------------------------- #define BOOST_SCOPE(name) \ if (const bool LABELED_SCOPE_##name = false){break(name); name:;} else
#define break(name) \ (void)LABELED_SCOPE_##name; goto name; --------------------------------------------------- Now we can write:
BOOST_SCOPE(a) { break(a); cout << "123\n"; }
The real world usage would reside in nested loop&switch where labeled-break really shines.
Thoughts? Sorry if this idea is too simple and somewhat rejected before...
It's a nice thought but: (a) I think the situation where you want to break and/or continue more than one loop-level out at a time is rare; and Agree and its use /could/ be a sign that a refactoring is needed, but not always. (b) in those rare situations, explicitly using gotos and labels (with a descriptive name) is reasonably brief and readable; so I would be hesitant to adopt this.
When we use label/goto directly there is a risk that the user goto to the label without constructing all the scoped variables, v in this case. if (cnd3) goto L; // bad as v constructor will not be called. { T v; for(;;) { while (cnd) { if (cnd2) goto L; // go to [1] } } L: // [1] std::cout << v <<std::endl; } With named blocks this code will just not compile. if (cnd3) BOOST_BREAK(L); // compile fail: only allowed from inside the block. { T v; BOOST_NAMED_BLOCK(L) for(;;) { while (cnd) { if (cnd2) BOOST_BREAK(L); // go to [1] } } // [1] std::cout << v <<std::endl; } Best, Vicente

2013/1/16 Vicente J. Botet Escriba <vicente.botet@wanadoo.fr>
Le 15/01/13 18:44, Jeffrey Lee Hellrung, Jr. a écrit :
On Sun, Jan 13, 2013 at 4:30 AM, TONGARI <tongari95@gmail.com> wrote:
Hi all,
One of the few things I appreciate in Java is the labeled-break feature. I think C++ would provide it as well in future standard but it seems that there's no even such a proposal.
In lack of the language feature, a simple emulation can be used:
------------------------------**--------------------- #define BOOST_SCOPE(name) \ if (const bool LABELED_SCOPE_##name = false){break(name); name:;} else
#define break(name) \ (void)LABELED_SCOPE_##name; goto name; ------------------------------**--------------------- Now we can write:
BOOST_SCOPE(a) { break(a); cout << "123\n"; }
The real world usage would reside in nested loop&switch where labeled-break really shines.
Thoughts? Sorry if this idea is too simple and somewhat rejected before...
It's a nice thought but:
(a) I think the situation where you want to break and/or continue more than one loop-level out at a time is rare; and
Agree and its use /could/ be a sign that a refactoring is needed, but not always.
(b) in those rare situations, explicitly using gotos and labels (with a
descriptive name) is reasonably brief and readable; so I would be hesitant to adopt this.
When we use label/goto directly there is a risk that the user goto to the label without constructing all the scoped variables, v in this case.
if (cnd3) goto L; // bad as v constructor will not be called. { T v; for(;;) { while (cnd) { if (cnd2) goto L; // go to [1] } } L: // [1] std::cout << v <<std::endl; }
Actually this won't compile if T is not a POD.

Le 16/01/13 13:20, TONGARI a écrit :
2013/1/16 Vicente J. Botet Escriba <vicente.botet@wanadoo.fr>
Le 15/01/13 18:44, Jeffrey Lee Hellrung, Jr. a écrit :
(b) in those rare situations, explicitly using gotos and labels (with a
descriptive name) is reasonably brief and readable; so I would be hesitant to adopt this.
When we use label/goto directly there is a risk that the user goto to the label without constructing all the scoped variables, v in this case.
if (cnd3) goto L; // bad as v constructor will not be called. { T v; for(;;) { while (cnd) { if (cnd2) goto L; // go to [1] } } L: // [1] std::cout << v <<std::endl; }
Actually this won't compile if T is not a POD.
You are right. Sorry for the noise. Vicente
participants (7)
-
Alex Perry
-
Brian Ravnsgaard Riis
-
Jeffrey Lee Hellrung, Jr.
-
Klaim - Joël Lamotte
-
Rob Stewart
-
TONGARI
-
Vicente J. Botet Escriba