break seen as a C archaism
john.r.rose at oracle.com
Thu Mar 15 21:58:28 UTC 2018
On Mar 15, 2018, at 2:13 PM, Maurizio Cimadamore <maurizio.cimadamore at oracle.com> wrote:
> So, from a language design perspective, 'return x' is wrong - but, as you point out, we already committed the original sin of having 'return == local return' for lambdas, so I'm not too convinced that we couldn't use the same story again here. E.g. when you say 'return', what you really mean is 'returning from the innermost context'. This could be a method (as usual), or a nested expression e.g. a lambda or a switch expression.
We have method bodies and lambda bodies on one hand,
and we have switches and loops on the other.
We use return to escape from the former, and break to
escape from the latter.
Note that return may or may not take an expression,
while break never does, at present.
So far so good. Now we stir in expression switches.
Which side of the fence do they belong on?
It seems to me that your position needs to argue
that e-switches belong with methods and lambdas,
because only return can take an expression.
If you can pull this off, then break doesn't need
to take an expression.
Likewise, my position need to argue that giving "break" an
expression is reasonable. I don't need to argue
that expression switches are similar to legacy
switches. (But I'm trying to spike the argument
that it's hard to unify e-switches and s-switches,
so let's just fork the language with a new switch-like
feature for expressions.)
But there are two reasons why e-switch doesn't
belong with method body and lambda body,
a shallow but strong one, and a deep one.
Shallow but strong: e-switches are obviously switches.
Deep: Lambda bodies and method bodies execute
in their own stack frames. Any up-level references
must be to final locals (or fields). Lambda bodies
and methods can execute at most one "return",
which tears down their frame. Expressions,
including expression switches, execute in the
frame of the containing lambda body or method
and can read *and write* local variables.
Expressions are inherently local to a frame
and can imperatively side effect it.
A "return" which in some contexts keeps the
stack frame and jumps somewhere is a weaker
return than today's return. (Weaker meaning
less can be concluded by observing it in code.)
So I can't group e-switch cases with lambda bodies.
I know some have performed this feat to their own
satisfaction, but it's hard for me, in a way that
seems deeper than just learning curve.
By now we recognize that adding an expression
to "break" is no big deal; it's a new overloading.
I agree that it is open to the accusation that it's not
thrifty, that "return" already does that job.
But it seems to me the shallow and deep points
above answer the accusation.
For me, the cost of making "break" do a new
trick is paid for by the benefit of not inventing
a new switch-like expression (like ?: for if/else),
and not having to weaken "return".
More information about the amber-spec-observers