Switch expressions -- some revisions

Brian Goetz brian.goetz at oracle.com
Tue Dec 19 20:21:41 UTC 2017


Updated.

On 12/19/2017 3:03 PM, Guy Steele wrote:
> 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 <brian.goetz at oracle.com 
>> <mailto:brian.goetz at oracle.com>> wrote:
>>
>> 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/407b779e/attachment.html>


More information about the amber-spec-experts mailing list