This project is read-only.

Explicit block break and continue

Topics: C# Language Design
Jun 4, 2014 at 3:04 PM
Read: http://dlang.org/statement.html#ContinueStatement

So Instead of:
for(...)
{
   for(...)
   {
      ...
      goto OuterForEnd;
      ...
   }
   ...
   OuterForEnd:;
}
we can write:
outerFor:
for(...)
{
   for(...)
   {
      ...
      continue outerFor;
      ...
   }
   ...
}
This is much more readable form.
Oct 6, 2014 at 2:20 PM
Not only much more readable, but also the meaning of the statement becomes immediately clear.
Oct 6, 2014 at 2:49 PM
JesInc28 wrote:
Read: http://dlang.org/statement.html#ContinueStatement

So Instead of:
for(...)
{
   for(...)
   {
      ...
      goto OuterForEnd;
      ...
   }
   ...
   OuterForEnd:;
}
we can write:
outerFor:
for(...)
{
   for(...)
   {
      ...
      continue outerFor;
      ...
   }
   ...
}
This is much more readable form.
I don't like the need for a magic label.

How about a chain of jump statements?
jump-statement-chain:
    intermediary-jump-statement-chain(opt) final-jump-statement(opt)

intermediary-jump-statement-chain:
    intermediary-jump-statement
    intermediary-jump-statement-chain intermediary-jump-statement

intermediary-jump-statement:
    break-statement
    continue-statement

final-jump-statement:
    goto-statement
    return-statement
    throw-statement
This way you can declare whatever you want to happen. You can break the nearest enclosing cycle, continue on the next one and throw in the end:
for (...)
{
    while (...)
    {
        foreach (...)
        {
            ...
            continue break return;
            ...
        }
    }
}
It's not pretty, but, at least, we leave labels for __goto__s.
Oct 7, 2014 at 8:54 AM
Why do you say magic label? It is simply a label which, attached to a cycle-like statement, acts as a controller for that statement.

In addition to D, for example:
I admit that I don't like goto statements, even in a more "careful" fashion than C. I think that labeled/numbered break and continue statements naturally extend the standard non-labeled/numbered versions, without the need to fall back to a goto.

What should be the behavior of a jump statement chain? When you issue a control statement for a cycle which does not directly enclose the statement itself, you are implicitly break-ing all the intervening cycles:
whileCycle:
while (...)
    {
    forCycle:
    for (...)
    {
        ...
        continue break; // What does continue mean?
    }
}
That is: if whileCycle is broken, also forCycle necessarily is.
Oct 7, 2014 at 2:22 PM
FstTesla wrote:
whileCycle:
while (...)
    {
    forCycle:
    for (...)
    {
        ...
        continue break; // What does continue mean?
    }
}
That is: if whileCycle is broken, also forCycle necessarily is.
Yep! Silly me. That should be _break* continue?_. continue should also be final.
Oct 7, 2014 at 2:33 PM
Edited Oct 7, 2014 at 2:49 PM
I like JsInc28's suggestion. In addition to continue <label> I'd like to see a break <label> to be able to break out of multiple loops.

Since labels in front of a loop would have slightly different semantics compared to ordinary goto destinations (they are no longer jump destinations but label a loop), it could make sense to format them as follows:
outerFor: for (...)
{
   for (...)
   {
      ...
      continue outerFor;
      ...
   }
   ...
}
PHP's numbered branch statements look okay, too. With numbers you do not have to come up with labels for the loops but they make it easy to introduce bugs in case one wants to add or remove loops.

Jump chains could be another solution although I do not see the point of final-jump-statement. But e.g. break break; to express a break out of two loops does look good to me.
Oct 7, 2014 at 2:38 PM
PauloMorgado wrote:
That should be _break* continue?_. continue should also be final.
That's it. Of course return and throw exit from the method, so ALL cycles are implicitly broken, and goto keeps the semantics unchanged.

So you suggest:
jump-statement:
    cycle-exit-statement-chain
    goto-statement
    return-statement
    throw-statement

cycle-exit-statement-chain:
    break-statement cycle-exit-statement-chain[opt]
    continue-statement
Oct 7, 2014 at 5:23 PM
What's wrong with plain old goto? Both the goto statement and the target label shout quite loudly "HEY THERE'S SOMETHING UNUSUAL GOING ON HERE". Excessive of goto is much like crying wolf--if one does it too much, the places that really need attention may not receive it. Further, some usage patterns for goto can make code hard to follow.

I really don't like the way Java puts break labels before a loop when the target of the break is not the start of the loop but rather the following code. If one does want to use breaks with labels, I think a cleaner syntax would be:
while(whatever)
{
    for (whatever)
    { :|MIDDLE|:
      while(whatever)
      {
        if (condition) break OUTER;
        if (condition) continue MIDDLE;
      }
    }
} :|OUTER|:
The parser would have to scan ahead a little following the close-brace for the loop to see if the next character was a colon, but I don't think there would be any present syntactic ambiguity nor can I think of any other potential purpose for such syntax that would be foreclosed by allowing it to be used for loop labels. My inclination would be to require that loops be labeled at the top (using the indicated syntax which is slightly different from goto labels) if used with labeled continue, and at the bottom if used with labeled break. One identifier could be used with both break and continue if and only if the identifier appeared at the top and bottom of the same loop.

PS--Conceptually, I'd like the loop-start label to appear between the loop control statement and the opening brace, but I can't figure out how to not have that look ugly.
Oct 8, 2014 at 8:58 AM
supercat wrote:
What's wrong with plain old goto? Both the goto statement and the target label shout quite loudly "HEY THERE'S SOMETHING UNUSUAL GOING ON HERE".
You're right, maybe too loudly. While goto can be used quit freely (i.e. no one prevents you to put the target label anywhere, and one has to "inspect" the code to find what's going on), on the contrary break and continue convey a precise message.
Take a look to these 1-level-deep examples:
for (...)
{
    ...
    if (...) continue;
    ...
}

for (...)
{
   ...
   if (...) goto label;
   ...
   label:;
}
These are of course equivalent, but the first one is clearly saying "skip and go on to the next iteration", while the second is just saying "jump somewhere", with no immediate evidence that I'm jumping to the end of the iteration, until I go and see where the target label is". In fact, a goto could be used to jump anywhere (within the specification rules)
Now generalize the example to a n-level-deep situation: C# has no way to do this trick and is forced to fall back on gotos. Other languages can instead, some with labels on loop statements, other ones by indicating the depth of the "exit" statement.

supercat wrote:
I really don't like the way Java puts break labels before a loop when the target of the break is not the start of the loop
That is because Java does not use labels to target statements (like in C#), but to identify statements. Java has no goto (well, the keyword exists but is unused on purpose), when on the contrary C# only uses labels for gotos. These are quite complementary situations, so maybe labeled break and continue statements would collide with the current way labels are exploited.
Oct 8, 2014 at 4:43 PM
FstTesla wrote:
supercat wrote:
What's wrong with plain old goto? Both the goto statement and the target label shout quite loudly "HEY THERE'S SOMETHING UNUSUAL GOING ON HERE".
You're right, maybe too loudly. While goto can be used quit freely (i.e. no one prevents you to put the target label anywhere, and one has to "inspect" the code to find what's going on), on the contrary break and continue convey a precise message.
A break or continue which leaves more than one levels of nesting should say somewhat noticeably that there's something usual going on. I don't think the "goto"'s level of volume is particularly excessive, though an intermediate level wouldn't be a bad thing.
supercat wrote:
I really don't like the way Java puts break labels before a loop when the target of the break is not the start of the loop
That is because Java does not use labels to target statements (like in C#), but to identify statements. Java has no goto (well, the keyword exists but is unused on purpose), when on the contrary C# only uses labels for gotos. These are quite complementary situations, so maybe labeled break and continue statements would collide with the current way labels are exploited.
I would expect that more often than not, the first thing someone reading a control statement will generally want to know is where the code is going next. If the next code to execute is located further down in the source, having to search higher up in the source code to find the label seems less than useful.

That having been said, I was just thinking there might be some advantage to having a "block-label" syntax which would allow labels to be placed at the top and bottom of a brace-delimited block whether or not they were used for break or continue (but possibly requiring some extra punctuation if they were, so as to highlight that fact), and have the compiler validate that they match. I know I've seen a lot of programmers do things like:
for (int i=0; i<23; i++)
{
  ...
} // for (int i=0; i<23; i++)

which can be helpful, but is of course not validated by the compiler. If instead one could use something like:
for (int i=0; i<23; i++)
{|PreSearch|
  ...
|PreSearch|}
and have the compiler check that the label at the end of the block matches the one before, that could be helpful (visually, I think the beginning end end of the block pair off quite nicely; the pairing might be a little nicer without the pipe between the brace and label, but I would worry that depending upon what exactly was within the statement, parsing might be ambiguous without it if a parent class exposed an identifier named PreSearch.
Oct 9, 2014 at 8:26 AM
supercat wrote:
That having been said, I was just thinking there might be some advantage to having a "block-label" syntax which would allow labels to be placed at the top and bottom of a brace-delimited block whether or not they were used for break or continue (but possibly requiring some extra punctuation if they were, so as to highlight that fact), and have the compiler validate that they match.
If instead one could use something like:
for (int i=0; i<23; i++)
{|PreSearch|
  ...
|PreSearch|}
and have the compiler check that the label at the end of the block matches the one before, that could be helpful (visually, I think the beginning end end of the block pair off quite nicely; the pairing might be a little nicer without the pipe between the brace and label, but I would worry that depending upon what exactly was within the statement, parsing might be ambiguous without it if a parent class exposed an identifier named PreSearch.
This could be a good compromise. So if I understand well, this syntax should be allowed only for cycle-like statements for labeled break and continue. Otherwise, another position for the "piped labels" should be chosen, in order to remark that they are associated to the cycle, not to the block itself or even the first statement of the block.

Because the braces are not compulsory, the case where they are omitted must be considered too.
Oct 9, 2014 at 6:07 PM
FstTesla wrote:
Because the braces are not compulsory, the case where they are omitted must be considered too.
It would be possible to have a for loop contain a single for statement which controlled a brace-delimited block, and have code in the inner loop which would want to exit both loops. I would not think it unreasonable, however, to say that if code is going to use a named "break" or "continue" with a loop, that loop would be required to use the braces.

I also don't see any particular reason why the named-block concept would have to be limited to looping statements. I could see usefulness to being able to assert that one particular pair of braces mates with another regardless of the purpose of those braces; oftentimes, when an extra brace inadvertently gets moved into a piece of code, the first reported error will be at a location far beyond the point of the mistake. If a scope containing the accidentally-inserted brace was labeled at the top and bottom, however, the compiler or syntax highlighter would be able to flag that scope.