Switch expressions -- some revisions

Ali Ebrahimi ali.ebrahimi1781 at gmail.com
Thu Dec 14 22:28:16 UTC 2017

Hi Brain,

Can we say existing switch construct arms results void value (by break) but
we want to enhance that to results non-void values (using break by value).
In other word, the result type of existing switch construct is void but now
based on target type of switch construct can be non-void and it is required
to break by value.

Note:I'm deliberately avoiding 'return' term and use result term instead

On Fri, Dec 15, 2017 at 12:52 AM, Brian Goetz <brian.goetz at oracle.com>

> 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."


Best Regards,
Ali Ebrahimi

More information about the amber-spec-observers mailing list