Here’s another way of looking at expression switch. This is a
translation-centric view, but may be useful both as a mental model and as a
specification approach as well.
If I have an expression switch:
T y = switch (x) {
case A -> e;
case B -> f;
}
We could implement by desugaring the switch into the invocation of a synthetic
method:
T y = m$switch(x, a, b, ...)
where a, b, ... are locals mentioned in e and f. And m$switch() is:
- replace "case L -> e" with "case L: return e"
- replace case L -> block with "case L: block"**
- m$switch() is declared to throw any checked exceptions thrown by switch arms.
** This is exploiting the otherwise-unfortunate pun between local return and
nonlocal return.
Where does this leave us?
- Can't do nonlocal return out of an expression switch. That's good -- that's
what we wanted anyway.
- Can't reference mutable locals. That seems OK, but see below.
- Fallthrough in expression switches (other than OR patterns) is cleverly
prohibited by the syntax of switch expressions.
This mental model leaves us pretty close to where we thought we wanted to land
anyway (whether or not we actually translate like this.)
Note that the “effectively final” constraint is stronger than it needs to be to
support this model. The reason that captured locals of even stack-confined
lambdas need to be effectively final is that the capture point and the
invocation point of the lambda might be different, and so there would be two
credible answers for what the following program could print:
int x = 3;
Runnable r = () -> println(x);
x = 4;
r.run();
You could argue for either 3 or 4 here, so to eliminate the potential for
confusion (among other reasons) we say “no non-effectively-final captures”.
But, for an expression switch desugared as above, the capture point and
invocation point are guaranteed to be the same. So we could easily say that
its OK to reference (but not mutate) mutable locals in a switch expression, and
it would be consistent with the model given.
Note that “consistency” offers us no guidance here; in one approach we’re
consistent with lambdas but inconsistent with, say, conditional expressions
(which can reference and even mutate mutable locals.)
So, candidates for what happens here:
- like conditional expression — anything goes, locals can be mutated
- can read locals, but can’t write them — a reasonable position, but unlike
anything else so far
- like lambdas - effectively final locals only.
> On Dec 7, 2017, at 5:33 PM, Brian Goetz <[email protected]> wrote:
>
> We've separated out a package of standalone improvements to `switch` (switch
> expressions, case null, and case alternation) into their own JEP:
>
> https://bugs.openjdk.java.net/browse/JDK-8192963
>
>