Option 8 (“switch case (x) { … }”) is increasingly appealing to me, because it 
is completely compatible, flags the variant up front rather than at the end, is 
easily pronounced, and has a story that I think is simple to explain.

However, I would also like to offer this variant, which has two additional 
constraints and is perhaps in some sense “the switch statement we wish we had 
had all along”:


Option 9:  The statement “switch case (x) { … }” is like “switch (x) { … }” but 
insists that the value x be handled by some case clause.  It is a static error 
if any SwitchLabel of the switch statement begins with “default".  It is a 
static error if the set of case patterns is not at least optimistically total 
on the type of x (therefore it is impossible for the switch statement to 
silently do nothing), and you get residue checking.  It is a static error if 
the last BlockStatement in any SwitchBlockStatementGroup can complete normally. 
 It is a static error if any SwitchLabel of the switch statement is not part of 
a SwitchBlockStatementGroup.


(The effect of the two additional constraints is to prevent fallthrough and 
fallout.  Thus under this definition a “switch case” always transfers control 
to a nonempty set of BlockStatements that follows some switch label that begins 
with “case”, and those statements cannot fall through—even the last set of 
statements needs to have a “break” or something.  Draconian, perhaps even 
Procrustean, but opt-in.)


> On Aug 22, 2020, at 6:38 PM, Guy Steele <guy.ste...@oracle.com> wrote:
> 
> Option 8:  The statement “switch case (x) { … }” is like “switch (x) { … }” 
> but insists that the value x be handled by some case clause.  The switch body 
> cannot contain a default clause (static error if it does), and it’s 
> impossible for the switch statement to silently do nothing.  It’s a static 
> error if the set of case patterns is not at least optimistically total, and 
> you get residue checking.
> 
>       enum Color { RED, GREEN }
>       Color x;
>       switch (x) { case RED: … }              // Okay
> 
>       enum Color { RED, GREEN }
>       Color x;
>       switch case (x) { case RED: … }         // static error: cases are not 
> optimistically total
> 
> Note that you can still use int and String types, but because default clauses 
> are forbidden, you have to use a total pattern instead:
> 
>       switch case (myString.length()) {
>               case 2: case 3: case 5: case 7: primeSquawk();
>               case 4: case 9: squareSquawk();
>               case int n: squawk(n);
>       }
> 
> I think this option clearly dominates options 4 and 7 (“switch enum (x)” and 
> “switch ((Color) x)”).
> 
> Note that it’s not completely redundant to allow “switch case” expressions as 
> well (which would ease refactoring), but the only extra constraint added by 
> “switch case” is that a default clause cannot appear.  If this option were 
> adopted, I suspect it would quickly become idiomatic to use “switch case” on 
> enums and many sealed types, and to use “switch” with a “default 
> <totalpattern>” clause in most other cases.
> 

Reply via email to