Good.
This sentence:
The sugared form of case arms of switch expressions may also throw
exceptions, even though throw e is a statement, not an expressions.
(“an expressions”??) could perhaps be replaced or augmented by this
syntactically more precise observation:
In a switch expression, we also define
case LABEL -> throw expression;
to be sugar for
case LABEL: throw expression;
Also, there is a formatting problem: the text line
System.out.println("Neither Foo nor Bar, hmmm..."); break 3; }
should have been part of the code in the preceding box.
> On Dec 19, 2017, at 2:40 PM, Brian Goetz <[email protected]> wrote:
>
> I've updated the JEP to reflect these proposed changes:
>
> https://bugs.openjdk.java.net/browse/JDK-8192963
> <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."
>>
>>
>