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.


Reply via email to