M
mathog
I am not a big fan of code that uses multiple returns in one function.
(I do it at times, but try not to.) However, without using goto,
eliminating the multiple returns leads either to a deeply nested series
of "if" blocks or a construct like this
int function(}{
int status = 0;
while(1) { /* this is NOT used as a loop */
if(something)break;
if(something_else)break;
status = 1;
break;
}
return(status);
}
This sort of while construct has a couple of problems:
1. It looks like it should be running in cycles, and the only thing
telling a programmer who stumbles onto it that it isn't is the comment -
or code analysis, and that takes time if the code is long.
2. If there are real loops used within this then an extra variable is
needed solely to carry the "break" up to the outer level.
3. It needs the final break, to force a loop to not be a loop, because a
loop construct is being used in a nonlooping context.
The final alternative, to use goto, is not a programming problem, but it
is a social one, since one will inevitably have to defend the use of the
"evil" goto, even though if used properly it does not result in
spaghetti code - here it actually simplifies the structure. I hate
those annoying exchanges, and admit that I avoid goto's even in some
cases where it would make sense to use them just so I never have to
waste time discussing the matter.
I think something like this would be a better syntax than the preceding,
but AFAIK it isn't part of C and it isn't even on the drawing board:
int function(}{
int status = 0;
once(label) { /* will not be confused with a loop */
if(something)break; //exits once()
if(something_else)break(label); //exits once()
while(1){ /* really a loop */
if(some_loop_ending_test)break; // exits while()
if(some_logic_ending_test)break(label); //exits once()
}
status = 1;
} /* target for break(label) */
return(status);
}
and of course these could be nested with the constraints that all labels
must be unique in function and break must be to the last line of an
enclosing once():
once(label1){
once(label2){
if(test1)break;
if(test2)break(label1);
}
/* other tests */
}
In terms of moving code around, for instance, when editing it, it seems
like it wouldn't be particularly problematical. If part of the contents
of once(label1) are moved into once(label2), for whatever reason, to
clean it up would only require a search and replace on the pasted block
for "break(label1)" -> "break(label2)". If an editing error is made the
compiler will catch labeled breaks to labels for structures that they
are not within.
Another way to go about this would be to provide a way to "label" any
pair of matched {} at the top bracket, so that "once" would not be
needed. For discussion sake, one such syntax would be "label:{", which
could be used any place a "{" is currently used. It looks very odd to
me in some contexts
if(test)first_test_set:{
if(test2)break(first_test_set);
//other stuff
}
but OK in others:
parity_tests:{
if(test)break(parity_tests);
// other stuff
}
Presumably there would be some conflicts between this syntax and the
existing C line label syntax, so the actual syntax for this sort of
label might be something else.
The equivalent "continue(label)" is suggested by symmetry, but maybe it
should be avoided because it would turn code that does not look like it
cycles, into code that does cycle. The labeled continue might be useful
though if its use was restricted to the innards of existing loops, like
a for(){} or a while(){}.
Any chance we will ever see something like this in a C language
standard? Labeled breaks are not required, of course, since we can do
the same things with existing structures, but it would certainly be
_convenient_ if something like this was available.
Regards,
David Mathog
(I do it at times, but try not to.) However, without using goto,
eliminating the multiple returns leads either to a deeply nested series
of "if" blocks or a construct like this
int function(}{
int status = 0;
while(1) { /* this is NOT used as a loop */
if(something)break;
if(something_else)break;
status = 1;
break;
}
return(status);
}
This sort of while construct has a couple of problems:
1. It looks like it should be running in cycles, and the only thing
telling a programmer who stumbles onto it that it isn't is the comment -
or code analysis, and that takes time if the code is long.
2. If there are real loops used within this then an extra variable is
needed solely to carry the "break" up to the outer level.
3. It needs the final break, to force a loop to not be a loop, because a
loop construct is being used in a nonlooping context.
The final alternative, to use goto, is not a programming problem, but it
is a social one, since one will inevitably have to defend the use of the
"evil" goto, even though if used properly it does not result in
spaghetti code - here it actually simplifies the structure. I hate
those annoying exchanges, and admit that I avoid goto's even in some
cases where it would make sense to use them just so I never have to
waste time discussing the matter.
I think something like this would be a better syntax than the preceding,
but AFAIK it isn't part of C and it isn't even on the drawing board:
int function(}{
int status = 0;
once(label) { /* will not be confused with a loop */
if(something)break; //exits once()
if(something_else)break(label); //exits once()
while(1){ /* really a loop */
if(some_loop_ending_test)break; // exits while()
if(some_logic_ending_test)break(label); //exits once()
}
status = 1;
} /* target for break(label) */
return(status);
}
and of course these could be nested with the constraints that all labels
must be unique in function and break must be to the last line of an
enclosing once():
once(label1){
once(label2){
if(test1)break;
if(test2)break(label1);
}
/* other tests */
}
In terms of moving code around, for instance, when editing it, it seems
like it wouldn't be particularly problematical. If part of the contents
of once(label1) are moved into once(label2), for whatever reason, to
clean it up would only require a search and replace on the pasted block
for "break(label1)" -> "break(label2)". If an editing error is made the
compiler will catch labeled breaks to labels for structures that they
are not within.
Another way to go about this would be to provide a way to "label" any
pair of matched {} at the top bracket, so that "once" would not be
needed. For discussion sake, one such syntax would be "label:{", which
could be used any place a "{" is currently used. It looks very odd to
me in some contexts
if(test)first_test_set:{
if(test2)break(first_test_set);
//other stuff
}
but OK in others:
parity_tests:{
if(test)break(parity_tests);
// other stuff
}
Presumably there would be some conflicts between this syntax and the
existing C line label syntax, so the actual syntax for this sort of
label might be something else.
The equivalent "continue(label)" is suggested by symmetry, but maybe it
should be avoided because it would turn code that does not look like it
cycles, into code that does cycle. The labeled continue might be useful
though if its use was restricted to the innards of existing loops, like
a for(){} or a while(){}.
Any chance we will ever see something like this in a C language
standard? Labeled breaks are not required, of course, since we can do
the same things with existing structures, but it would certainly be
_convenient_ if something like this was available.
Regards,
David Mathog