Hi,

May I jump in as an outsider and someone who's just using the language...

On 03/15/18 22:58, John Rose wrote:
On Mar 15, 2018, at 2:13 PM, Maurizio Cimadamore <maurizio.cimadam...@oracle.com <mailto:maurizio.cimadam...@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.

Yes, and my intuitive distinction between those two kinds of constructs is that the first are just "declarations" of code blobs, while the second are code blobs that execute in-line with the surrounding code. It is therefore very intuitive for me to have two kinds of syntax for exiting the constructs - "return" for the first and "break" for the second.

I don't know why others find break so archaic. When I 1st saw this proposal, I thought that break was very intuitive choice for e-switch.


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.

That's another, more technical way of saying: methods and lambdas are declarations of code, switches and loops are in-line constructs that execute "immediately" in the surrounding context. Lambdas do "capture" surrounding context, but they don't execute in it (they can't modify locals, do long returns etc.).

Speaking of long returns...

If return was used for "yielding" a result from e-switch, how is one supposed to do a return from a method inside the e-switch:

int m(int x) {
    int y = switch (x) {
        case 1: return 12; // I want to return from m() here!
    }
}


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

— John

I totally agree. There are some caveats though. What to do in situations like this, for example:

int var_or_label = 13;
int y = switch (x) {
    case 1:
        var_or_label: {
            break var_or_label;
        }
        // do we reach here?
};


The standard means that Java took to avoid ambiguities caused by new features was to prioritize old behavior (varargs for example). In above sample, label would take precedence. It is easy to choose the var:

    break (var_or_label);


And now for something completely different...

I think that with introduction of e-switch, we might soon see it being "abused" for things like:

doSomething(
    par1,
    switch (1) { case 1:
        // compute result...
       break resut;
    },
    par3
);

Are there any plans for such construct "without the boilerplate" ?-)

Among existing reserved words, "do" seems most appropriate:

doSomething(
    par1,
    do {
        // compute result...
       break resut;
    } while (false),
    par3
);

And if "while (false)" could be optional, we get:

doSomething(
    par1,
    do {
        // compute result...
       break resut;
    },
    par3
);

Combining with lambdas, we get 3 ways to do the same thing:

x -> y
x -> { return y; }
x -> do { break y; }


Regards, Peter

Reply via email to