JEP proposed to target JDK 12: 325: Switch Expressions (Preview)
brian.goetz at oracle.com
Tue Aug 28 00:02:55 UTC 2018
> The few objections raised here are not new, having already been raised
> and answered over on the amber-dev and amber-spec-experts lists. I’ve
> therefore targeted this JEP to JDK 12.
As Mark says, the issues raised on this thread were already considered
and discussed at some length during the design of the feature. But, for
the convenience of readers here, I will summarize for the record some of
the reasons why these suggestions were not incorporated into the final
design of the feature when they came around the first time.
Stephen raised several specific objections, which I'll summarize as:
- You're increasing complexity by adding three features, one of which
is silly, and which gives us more fallthrough rather than less, which is
surely a move in the wrong direction!
- I don't love the syntax.
- You should have created a new syntactic form (hereafter, "snitch",
for "new switch") and left classic switch for dead, rather than piling
more complexity on existing switch, because existing switch is
hopelessly tied to the dumb idea of fallthrough. Die, fallthrough, die.
Ben expressed general agreement, and specifically for the "you should
have killed switch and made something new" position. While I understand
where these opinions come from, and we did consider these issues
seriously, we concluded that abstracting the existing switch construct
as we did was a better long-term path.
Ben also raised the excellent point that language design is a balance
between the interests of experienced developers and of newcomers -- a
concern we struggle with in every single feature, and which also played
into our decision here.
The first sentiment, which I've seen expressed in a few places, relies
on a somewhat tortured notion of "feature". We have not added three
features (enhanced statement switch, classic expression switch, enhanced
expression switch), as much as added _two_ features, defined at a very
- The ability for switch to be an expression or a statement
- The choice of classic case labels or enhanced case labels, where the
latter are single consequent, fallthrough-free, and free of the
confusing scoping of the classic switch block (essentially, fixing most
of the things people complain about with respect to switch.)
These features work orthogonally, so that you can mix and match them
freely, and I don't think anyone could reasonably object that either is
frivolous or undesirable. So while they do give rise to four
combinations, these combinations are not features in themselves.
Defining the improvements to switch as orthogonal choices makes the
design and implementation _simpler_, not more complex, as we can then
reason about the semantics of a particular combination based on the
semantics of simpler orthogonal primitives.
The fact that some combinations of these features are more desirable
than others is not evidence that a mistake was made. This is often the
natural consequence of providing simple primitives that can be combined
orthogonally; some of the combinations are always going to be more
sensible than others, and that's fine. So while "classic expression
switch" may seem silly, and will almost certainly be rarely used in
practice, that doesn't mean that we should distort the language design
to prevent it. In fact, doing so would increase, not decrease, the
complexity, as it introduces arbitrary constraints and special cases.
(As a possibly tortured analogy, while we might almost never write a
combination of public setter and private getter, that's no reason to try
and outlaw that combination.)
As to syntax preferences ... because syntax is so deeply subjective,
there is never going to be a syntax that satisfies everyone. And,
people being what they are, they tend to only complain about the things
they disagree with, and are quiet about the things they agree with. So
any syntax decision (whatever it is) is going to be met with some degree
of "I don't like it" or "I would have preferred X" -- but again, that
isn't necessarily actionable or dispositive. The syntax choice we made
here is consistent with how similar things are done in similar languages
-- and we think it will, perhaps after a few days of initial
brain-retraining, be well-understood and accepted by Java developers.
The final concern is a combination of pragmatism and language evolution
philosophy -- whether it is better to abandon an existing feature and
create a replacement, or to try and rehabilitate or generalize an
existing feature. While we asked ourselves many times whether switch
could indeed be rehabilitated (not just in the context of this smaller
feature, but in the context of the bigger feature arc of pattern
matching), we found that, at each turn, it was more practical to
rehabilitate it than one might have initially thought. And we felt it
better to build on the existing feature that is well understood and well
documented, than to create a wholly new one, just because the old one
Ben expressed concerns along the lines of "think of the students" with
respect to the proliferation of switch forms, but the reality with a
separate "snitch" form would most likely be worse. Students would not
be fully absolved of the need to learn "old switch", not only because
they will encounter code that uses it, but because snitch would almost
certainly be tilted towards the "happy cases", which, while common, are
not universal. And by un-anchoring snitch from switch, the differences
would likely be more arbitrary. So new students would encounter a
language with two suspiciously similar constructs, but subtly different
in harder-to-understand ways, and wonder why there are two ways to do
it. The burning hulk of "old switch" would lie forever on the roadside,
but unable to be ever hauled away. Its nice to think that we can invent
the ideal "snitch" construct, and just leave "switch" in the past, but
that's a fantasy.
Now, if switch were truly broken, it might be different. But for all
the distaste of fallthrough-by-default, the existing switch construct is
_not_ fundamentally broken; it's not just what we'd design now if we had
a clean sheet of paper. (BTW, fallthrough itself is not a problem, and
sometimes is essential; the real mistake was fallthrough _by default_.)
Therefore, while we did consider whether it would be necessary to retire
"switch" to pasture, we found no evidence that this was actually
necessary -- and found that it was possible to enhance switch to support
all the desired behaviors, rather than to abandon it, however tempting
the latter course might initially seem. Enhancing switch builds on the
existing understanding of Java developers; abandoning it for snitch
invalidates that understanding.
At a meta level, this inclination -- "just abandon switch and build
something better" -- illustrates a common temptation that is best
avoided: over-rotating towards the desire to "fix" the mistakes of the
past because they offend us, and because the current opportunity seems
"the last chance" to right a wrong that's been bugging us for years.
These are natural motivations, but they are frequently siren-songs that
lure us away from the path that calmer reason might otherwise have
chosen. Yes, it would have been better if switch were designed
differently 20 years ago, but that was billions of programmer-hours and
lines of code ago, and the calculus is very different with such a large
existing base of code and user understanding. So, while I understand
why it feels like an "opportunity missed", the cost of "seizing" this
opportunity was too great, and the benefit too small. Its natural to
regret that we can't fix the mistakes of the past, but in this case, it
would have been the wrong choice.
The preview mechanism will allow us to gather feedback on the feature
from actual use, rather than theorizing from no examples, and
potentially adjust the specification before final release if warranted.
So if any _new_ issues up come as a result of actual experience, we are
happy to hear about them.
More information about the jdk-dev