Make all switches exhaustive?

Brian Goetz brian.goetz at oracle.com
Tue Apr 27 17:11:18 UTC 2021


Maurizio's comment got me thinking about a possible way to eliminate the 
sharp edge of "sometimes switches are type-checked for exhaustiveness, 
and sometimes not."

Historically, there is no requirement that switches be exhaustive; 
legacy switches without a default are like unbalanced ifs.  (Notably, 
though, the DA rules do distinguish between switches with and without a 
default, and switches implicitly reject any null remainder -- so we 
still do have a solid base to build on here.)

When we did expression switches, we said "expression switches must be 
total."  This was a forced move if we wanted to reuse "switch", because 
expressions must be total and compatibility backed us into letting 
statement switches be partial. Unfortunately, this leaves statement 
switches with less type checking than expression switches, since there 
is no way to even opt into exhaustiveness checking.

As switch gets more powerful (e.g., switching over sealed types with 
patterns), this lack of exhaustiveness checking becomes a bigger deal.  
We'd been imagining that we'd have to "patch" switch to allow opting 
into exhaustiveness checking, but maybe there's another way.

As we are about to dramatically extend the power of switch (by 
permitting pattern labels, and allowing switches on other types than 
integers, boxes, strings, and enums), what we could do is:

  - Erroring on non-exhaustive non-legacy statement switches now;
  - Warning on non-exhaustive legacy statement switches now;
  - Later upgrading these warnings to errors, after a period of time 
where people can update their code.

The world we end up in in the long run is: all switches are exhaustive, 
with no new language surface for managing exhaustiveness.

Legacy switches are those whose operand type is one of the "classic" 
types and all labels are constant labels or "default".

For a switch that is deliberately non-exhaustive, all the user has to do 
to capture this (and shut up the compiler) is:

     default: break;

which is not very intrusive, and arguably makes the code more readable 
anyway.  Users will see a speed bump when upgrading to pattern switches 
(clippy will tell them "I see you're writing a pattern switch, don't 
forget to end it with default:break") which presumably they will quickly 
internalize.

(How's that for teaching an old dog new tricks?)

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.java.net/pipermail/amber-spec-experts/attachments/20210427/1190f3b0/attachment.htm>


More information about the amber-spec-experts mailing list