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. >