Dear Experts,

As we put the final polish on features for JDK20, we noticed that we have an 
opportunity to make a very small breaking change (as part of the preview 
feature) to simplify our lives. I’m writing to see what you think.

tldr: A switch expression over an enum class should throw MatchException rather 
than IncompatibleClassChangeError if no switch label applies at runtime.

Details:

When we introduced switch expressions, we opted for a design where the switch 
body had to be exhaustive. When switching over an enum type, a switch body with 
case labels supporting all the enum constants for the enum type is considered 
exhaustive, meaning a default clause is not needed.

However, there is a possibility that the enum class is changed after 
compilation of the switch expression, and a new enum constant added. Then when 
executing the switchexpression, no label would apply.

The question we faced in JDK14 was what to do at this point. We decided on 
IncompatibleClassChangeError as that was a pre-existing exception that was 
generally understood by developers as a signal that things have got out of sync 
and re-compilation is needed.

Back to the present day, with the support of pattern switches, we can now write 
switches over a sealed type. When switching over a sealed type, a switch body 
with case labels with type patterns matching all the permitted subclasses is 
considered exhaustive, meaning a default clause is not needed.

If the sealed hierarchy has been changed after compilation of the switch, it is 
possible that when executing the switch that no label would apply. In this case 
we have settled on throwing a MatchException.

Throughout our design process, we have noticed the connection between enum 
classes/enum constants and sealed class/permitted subclasses – they are 
essentially the same thing up the term/type hierarchy. Moreover, in a future 
release, we plan to support case labels with a mix of sealed class type 
patterns and enum constants.

But we now have an inconsistency - one throws IncompatibleClassChangeException 
in a bad situation and the other MatchException which will make this future 
development almost impossible. We need these cases to throw the same exception: 
MatchException. So we propose to make the small breaking case to the language 
that switch expressions over enum classes throw MatchException should no switch 
label apply in the switch body.

People who deliberately change their enum classes by adding new constants, and 
do not recompile their switches over this enum class, and rely on this throwing 
ICCE will notice this breaking change. We think this is a vanishingly small set 
of developers. The vast majority of developers, on the other hand, will thank 
us for this unification, especially if it enables other new features down the 
road.

What do you think?

Thanks, 
Gavin

Reply via email to