Switch expressions -- some revisions
Brian Goetz
brian.goetz at oracle.com
Tue Dec 19 19:40:50 UTC 2017
I've updated the JEP to reflect these proposed changes:
https://bugs.openjdk.java.net/browse/JDK-8192963
On 12/14/2017 4:22 PM, Brian Goetz wrote:
>
> After reviewing the feedback on the proposal for switch expressions,
> and a bit of going back to the drawing board, I have some proposed
> changes to the plan outlined in the JEP.
>
>
> 1. Throw expressions. While throw expressions are a reasonable
> feature, many expressed concern that if permitted too broadly (such as
> in method invocation context), they would encourage "tricky" code for
> little incremental expressiveness. The real need here is for arms of
> expression switches to be able to throw when an unexpected state is
> encountered; secondarily it may be useful allow a value-bearing lambda
> to unconditionally throw as well. But extending this to &&, ||,
> assignment, and method invocation context seems like asking for
> trouble. So we'll narrow the treatment here, allowing throw on the
> RHS of a switch expression ARM, and possibly also the RHS of a lambda.
> (This doesn't close any doors on making `throw` an expression later,
> if desired.)
>
>
> 2. Local return from switch. In the proposal, we borrowed the
> convention from lambda to use "return" for nonlocal return, mostly on
> the theory of "follow the arrow". But this is pretty uncomfortable,
> made worse by several factors: a) despite the syntactic similarity, we
> don't follow exactly the same rules for case arms of expression
> switches as for lambdas (such as treatment of captured vars), and b)
> when refactoring from statement switch to expression switch or vice
> versa, there's a danger that an existing "return" could silently swap
> between nonlocal and local return semantics.
>
> So we dusted off an old idea, which we'd previously explored but which
> had some challenges, which is to use "break" with an operand instead
> of "return" to indicate local return in switch expressions. So:
>
> int y = switch(abs(x)) {
> case 1 -> 1;
> case 2 -> 2;
> case 3 -> 3;
> default -> {
> println("bigger than 3");
> break x;
> }
> };
>
> The challenge is ambiguity; this could be interpreted as a nonlocal
> break out of an enclosing loop whose label is `x`. But then we
> realized that if `x` is both a variable and a label, we can just
> reject this, and tell the user to rename one or the other; since
> alpha-renaming the label is always source- and binary-compatible, the
> user has at least one (if not two) reasonable choices to get out of
> this problem.
>
> The benefit here is that now "break" means basically the same thing in
> an expression switch as it does in a statement switch; it terminates
> evaluation of the switch, providing a value if one is needed. Having
> addressed the ambiguity problem, I think this is a slam-dunk, as it
> aligns expression switch and statement switch quite a bit (same
> capture rules, same control flow statements.) We can also, if we like,
> support "break" for local return in lambdas (we should have done this
> in 8), to align the two.
>
>
> 3. (Optional.) There's room to take (2) farther if we want, which is
> to complete the transformation by eliminating the fake "block
> expression" in favor of something more like existing switch. The idea
> would be to borrow from statement switches, and rewrite the above
> example as (note where we use colon vs arrow):
>
> int y = switch(abs(x)) {
> case 1 -> 1;
> case 2 -> 2;
> case 3 -> 3;
> default:
> println("more than 3");
> break x;
> };
>
> So in this context, then "case L -> e" in an expression switch is just
> sugar for "case L: break e". As with lambdas, I expect the
> statements+break form to be pretty rare, but we still need to have a
> way to do it (not all objects can be created in a single expression
> without resorting to stupid tricks.)
>
> A good way to think about this is that this is leaving statement
> switch completely alone, and then expression switch "extends"
> statement switch, adding the nice arrow shorthand and the
> exhaustiveness analysis. The downside is that expression switch is
> even more "infected" by existing switch semantics, but after thinking
> about it for a while, this doesn't bother me. (It's more uniform,
> plus its considerably harder to make the "accidental fallthrough"
> mistake in an expression switch than a statement switch.)
>
> I expect this proposal will be a little more controversial than (2) --
> mostly because some are probably holding out hope that we'd radically
> rework existing switch -- but it has the major advantage of further
> building on existing switch, and also refrains from introducing a
> similar but different kind of fake block expression. Overall this is
> is more of a "build on what's there" solution, rather than "add
> something new in the gap."
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openjdk.java.net/pipermail/amber-spec-experts/attachments/20171219/5b607c55/attachment.html>
More information about the amber-spec-experts
mailing list