Switch expressions -- some revisions

Kevin Bourrillion kevinb at google.com
Thu Dec 14 21:41:49 UTC 2017

On Thu, Dec 14, 2017 at 1:22 PM, Brian Goetz <brian.goetz at oracle.com> wrote:

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 choice of `break` here feels very uncomfortable to me. The whole nature
of expression switch is that you never have to mess around with your
control flow the way you do in statement switch. The idea that you're
"breaking" out of anything doesn't apply in this world, so it just feels
opportunistic to repurpose the keyword for something else.

I understood `return` and I'm trying to figure out if the problems you
describe with it are really that harmful.

And if they are that harmful... would we consider just removing the keyword
and allowing this block to end with a naked expression?  i.e., you have
zero or more statements, followed by one expression. I don't know if this
is good or bad.

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.

This technically dispenses with the conflict, but that the conflict even
exists at all between two such unrelated constructs (an expression and a
label) is very weird.

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.

I'm not (currently) seeing it this way at all. It seems a superficial
similarity. In one form of switch you are responsible for control flow and
in the other you don't need to worry about it. It fits, to me, that you
should only see `break` in the former.

> We can also, if we like, support "break" for local return in lambdas (we
> should have done this in 8), to align the two.

(Seems even weirder to me?)

> 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;
>     };

Not liking the mixed motif here.

Just my 1 1/2 cents, that's all.

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

Kevin Bourrillion | Java Librarian | Google, Inc. | kevinb at google.com
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openjdk.java.net/pipermail/amber-spec-experts/attachments/20171214/a014e713/attachment-0001.html>

More information about the amber-spec-experts mailing list