Expression switch - an alternate proposal
Brian Goetz
brian.goetz at oracle.com
Mon Apr 9 14:28:40 UTC 2018
> The goal is to tackle four specific things (in order):
> 1) The context as to whether it is a statement or expression switch
> (and thus what is or is not allowed) is too remote/subtle
> 2) Mixing arrows and colons is confusing to read
> 3) Blocks that do not have a separate scope
> 4) Fall through by default
> while still keeping the design as a unified switch language feature.
It's great you specified your goals clearly. That automatically makes
it much more relevant. (But, it does let me pick on your goals.)
I think (1) and (2) are valid concerns -- they are driven by "what will
users think when they read this code." We care about that a lot.
I think (3) is firmly in the "fixing the mistakes of the past"
category. If it came for free, then fine, its a nice-to-have -- but
even then we should be careful. (I'll share that, in the course of
working out pattern binding scoping, one of the candidates appeared to
have the benefit of fixing (3) "for free", which we liked, but clearly
we gave this side-benefit too much weight, because this aspect kept us
from seeing an obviously better answer for quite a while. Lesson: even
free isn't free.)
On (4), I think you might have been under the mistaken impression that
we'd already decided on unrestricted fallthrough in expression switches?
It has always been on the list to work out the appropriate set of
restrictions, if any, for expression switches. (Obviously we're not
doing anything for statement switches.)
> To tackle #1 and #2, all cases in an expression switch must start with
> arrow -> (and all in statement switch must start with colon :)
> To tackle #3, all blocks in an expression switch must have braces
> To tackle #4, disallow fall through in expression switch (or add a
> fallthrough keyword)
Heh. This was essentially our starting point, with the exception that
we hadn't yet thought of reusing "break" in expression switches at that
point. So I obviously can't criticize it too much...
One serious problem this proposal had the first time around was that
there wasn't a way to express OR patterns, the expression equivalent of:
case Foo(var x):
case Bar(var x):
Even those who hate fallthrough agree that this kind of fallthrough is
essential, but no one could stand the notation:
case Foo(var x) ->
case Bar(var x) -> e;
We later came around to allowing comma-separate patterns as an explicit
OR mechanism:
case Foo(var x), Bar(var x) -> ...
which provided a way out of this mess. It also provided us with the
_option_ to restrict fallthrough into -> cases, which we didn't have
before.
> Here is the impact on some code:
>
> default: -> {
I assume you mean
default -> { }
> How is this still a unified switch?
By redefining "unified", of course :)
The differences here are, not surprisingly, almost entirely
syntax-driven, and go all the way down to the parser productions.
Expression switches have arrows and blocks; statement switches have
colons and no blocks. (The other proposed changes, comma-separated
label lists, alternate target types, and null case handling are the same
either way.)
The primary non-syntactic difference is that started with a "no
fallthrough ever in expression switch" requirement, whereas we're still
deciding on what constraints to put on fallthrough. But that's not a
difference, as much as you've already made up your mind and we haven't.
As syntaxes go, there's nothing deeply wrong with it, and I understand
your motivations (1) and (2) to prefer having a broader syntactic
difference between the two. That said, I have a real aversion to
introducing a block expression syntax here. It would suck to have a
block expression syntax that's only good in switches; it would suck in
different ways to have one that is good everywhere. So IMO the best way
to win that game is not to play. (IOW: one of the benefits of sticking
more literally with an existing construct is it avoids the need to
invent downstream new constructs like ad-hoc block expressions; one of
the problem with such ad-hoc features is the inevitable call to expand
their scope later.)
So, what you've done is move a little bit down "it looks different, so
people won't be surprised that it acts different" (e.g., different
exhaustiveness behaviors) spectrum. (You could go farther down that
spectrum by having a different keyword.) Of course, everyone will have
their own thoughts of how #{ DIFFERENT } the new feature has to look to
avoid confusing people.
Personally, I think the "people will be confused" issue is just the
usual Stroustrup's Rule in action. I think the vast majority of
expression switches will have all arrows except for maybe the default
clause, so I don't think in practice any one will actually be confused
that they're in an expression switch, nor do I think people will be
tempted to mix the two without knowing what they're doing. So I think
these fears are wildly overblown.
The conversation about fallthrough in expressions still has to be had,
so I won't comment there at this time.
I think we've mined this out pretty well. I'll move the discussion to
the EG list.
Cheers,
-Brian
More information about the amber-dev
mailing list