It’s time (actually well past time, if we hope to make the 13 train) to wrap up switch expressions.  

Overall, the consensus seems to be that the overall structure of the feature is correct; while some people might have preferred a different direction on the lump-vs-split choice, I don’t see any reason to change course over this.  The sole issue that we wish to address has to do with how, in the case where the RHS of a -> case, we indicate the value associated with that case when it is not a simple _expression_.  

In the first round, we overloaded “break” to accept a value in such switches.  This introduced two distortions:

- Ambiguity between “break label” and “break value” where the value is a simple identifier.  While the compiler is able to reason its way out of such ambiguities, we’re more concerned about the readability challenges posed to humans.  

- For compatibility and confusion reasons, in “breaky” constructs within the RHS of a -> case, such as a loop, you cannot break with a value through the loop to the enclosing switch _expression_.  

For that reason, there seems to be near-universal consensus that we choose another verb besides “break” in this context; when the keyword-resupply ship docked, the candidate of “break-with” was offered, with which people are generally OK.  But, since then, I’ve had some second thoughts on this — which I’ll “break” out into a separate e-mail.

If we back off to another keyword, then the first distortion goes away, and the second distortion can be corrected via the adjustments suggested by Gavin below.  

I believe the replacement of break with something else is the only open issue gating moving this feature forward.  Unfortunately, because the spec changes are nontrivial, I think it is best that we aim for re-previewing in 13 rather than finalizing.  (We have very little time left either way.)



On Apr 25, 2019, at 2:11 AM, Gavin Bierman <gavin.bier...@oracle.com> wrote:

Dear experts:

We are currently preparing a new JEP to make switch expressions a permanent feature. As stated on this list, we propose to replace the break with value form (e.g. break 42;) from the preview, with a new break-with statement (thus, break-with 42;), that is used to produce a value from an enclosing switch _expression_.

This gives us an opportunity to reconsider some earlier design decisions. One I’d like your opinion on regards the control statements and which statements can handle them. Brian sent a summary table to this list a while back that is very useful:

            break-e  break  break-l  continue  return
switch-e      H       X      X        X         X
switch-s      X        H      P        P         P
for/while/do  X        H      P        H         P
block         P        P      P        P         P
labeled       P        P      H*       P         P
lambda        X        X      X        X         H
method        X        X      X        X         H


where:

+ X – not allowed
+ P – let the parent handle it
+ H – handle it and complete normally
+ H* – handle it and complete normally if the labels match, otherwise P

The bit I’d like to reconsider is the break-e column. We initially decided that if a break-e occurred in a for/while/do or switch-statement, it would be super confusing if the break target was not this statement but an outer switch _expression_, even though it was a new form of break. So we proposed to ban it. For example:

  int i = switch (a) {
      default -> {
          switch (b) {
              case 0: break 0; // where does this transfer control?
          };
          break 1;
      }
  };

fails to compile:

  error: value break not supported in 'switch'
    case 0: break 0; // where does this transfer control?


However, now we are proposing a completely new break-with statement, perhaps the potential for confusion is reduced? The break-with statement can only be used to produce a value for a switch _expression_. So there should not be a confusion if that switch _expression_ contains a switch-statement or for/while/do statement. In other words, I would like to propose that we generalise the table to the following (changes in **-**):

            break-with  break  break-l  continue  return
switch-e      H           X      X        X         X
switch-s      **P**       H      P        P         P
for/while/do  **P**       H      P        H         P
block         P           P      P        P         P
labeled       P           P      H*       P         P
lambda        X           X      X        X         H
method        X           X      X        X         H


[It is useful to compare with the column for the return statement. This can return a value to the outer method/lambda regardless of any enclosing switch-statement or for/while/do statements.]

What do you think?
Thanks,
Gavin

Reply via email to