New JEP: Switch Expressions for the Java Language
Brian Goetz
brian.goetz at oracle.com
Fri Dec 8 15:01:06 UTC 2017
On 12/7/2017 6:28 PM, Liam Miller-Cushon wrote:
> I don't see it mentioned in the JEP, but will the default case of an
> expression switch be required to be last? (Previously:
> http://mail.openjdk.java.net/pipermail/amber-spec-observers/2017-November/000134.html)
We've not fully worked through these details yet. Here's my current
thinking.
We don't want to bifurcate the world into legacy switch and new switch.
Instead, we'd like to generalize switch, and then, where something makes
sense for (say) int switch but not for the general case, specify those
restrictions in terms of what's in the case labels. (For example (not
saying we will do this), take fallthrough. If we decided we were going
to kill fallthrough in patterns, rather than saying "no fallthrough in
pattern switch", we'd say "no falling into patterns of XYZ kind.")
The so-called-legacy switches have an interesting property; all their
cases, other than default, are mutually exclusive. (If you match "foo",
you can't match "bar".) This means that ordering is irrelevant (modulo
fallthrough.) OTOH, with more interesting switches, a case can subsume
another case, so its important that they be put in the right order
(having "case Object" before "case String" would mean the latter is
dead, and we treat this as an error.) In this light, "default" means
"case anything else", so if there's even a tiny bit of room for
confusion, it should go last.
What we do about existing switches is still open. For consistency[1],
we might want to remake the world to say "default goes last." But, this
has a cost (needless code churn, which will be viewed as ceremony), and
its not clear the consistency benefit is warranted. So we might say
something like "if any case label in the switch has a defined dominance
ordering with any other case label, default must be the last case."
That way old code continues to work, but once you migrate to nontrivial
patterns (which involves source changes anyway), you need to put things
right. This seems a good compromise.
For expression switch, we can be a little stricter, since there's no
existing code. On the other hand, its good to have the same set of
rules for expression and statement switch (all things being equal). So
this could go either way.
[1] Language-evolution arguments that start with "for consistency, ..."
are usually weak.
> > in the case of an enum switch that covers all known cases, a default
> clause can be inserted by the compiler that indicates that the enum
> definition has changed between compile time and runtime
>
> This sounds great, but note that it makes adding values to an enum a
> potentially source-incompatible change. Pattern switches that handle
> all values of an enum will need to be updated to handle the new value,
> or to have an explicit default.
Yes, but that doesn't bother me so much. Adding a member to an enum
that is exposed across compilation unit boundaries should be an unusual
case. If someone has explicitly coded defensively to deal with this,
great. If they haven't, having their switch code break when someone
else changes an assumption out from under them is a good thing.
Users (rightly) find it irritating that, when they define an enum:
enum TrafficLight { RED, YELLOW, GREEN }
that they constantly have to deal with "might be some other color." Not
all enums have this characteristic, but many do, and I think its
reasonable to let users err on the side of this assumption. They can
always code an explicit default if they want.
More information about the amber-spec-experts
mailing list