break seen as a C archaism

forax at univ-mlv.fr forax at univ-mlv.fr
Fri Mar 9 23:24:06 UTC 2018


----- Mail original -----
> De: "Brian Goetz" <brian.goetz at oracle.com>
> À: "Remi Forax" <forax at univ-mlv.fr>, "amber-spec-experts" <amber-spec-experts at openjdk.java.net>
> Envoyé: Vendredi 9 Mars 2018 23:15:21
> Objet: Re: break seen as a C archaism

> I understand where these people are coming from.  But my experience is,
> with a platform as mature as Java, one must be very, very careful of the
> desire to opportunistically "fix" "mistakes" of the past, it can be a
> siren song that draws you to the rocks.  I am skeptical of arguments
> that "we should kill break (or at least, not make it more important),
> because it's old stuff and we're young and hip", even though I have a
> certain sympathy for this argument.  (Well, I'm old, and was never hip,
> but I'd like to try it someday.)
> 
> Fallthrough is certainly one of the biggest punching bags of Java.
> However, the problem with fallthrough is not fallthrough itself, but the
> fact that fallthrough is the default, when 98% of the time you do not
> want fallthrough.  That's a separate problem -- and might admit a
> separate solution.
> 
> In switch expressions, 98% of the time, except maybe in the default arm,
> no one will ever have to type break, because you can usually say:
> 
>     int x = switch (y) {
>         case 1 -> 2;
>         case 2 -> 4;
>         case 3 -> 8;
>         default:
>             throw new TooBigException();
>     }
> 
> See, no break.  But sometimes, you will need it.
> 
> There are basically two stable ways we can go here:
>  - Renovate switch as best we can to support expressions and patterns.
>  - Leave switch in the legacy bin, and make a new construct, say
> "match".  (Note that doing this helps with the fallthrough-by-default,
> but doesn't really help switch expressions at all -- we still have to
> solve the same problem.)
> 
> There are costs to both, of course.  (Engineers tend to over-rotate
> towards the second because it seems more fun and modern, but sticking
> with what works, and what Java developers _already understand_, is often
> better.)  Our current strategy is to stick with what works until that
> approach is proven unworkable.
> 
> I think trying to "tame" switch is less stable; if we're going to stick
> with switch, we should avoid unnecessary discontinuities between make
> statement and expression switch.
> 
>> For others, it elevates the status of break and break is seen as something
>> wrong, an archaism from C.
> 
> I think this is really another form of the emotional "its ugly" reaction.
> 
>> When i asked what we should do instead, the answer is either:
>>    1/ we should not allow block of codes in the expression switch but only
>>    expression
> 
> This option is not only dislikable (as you suggest), but naive. While
> most of the time, you can say what you want in one expression, there
> will be times where you'll want to do things like the following:
> 
>     String y = switch (x) {
>         case 1:
>             System.out.println("DEBUG: found where the 1 is coming from!");
>             break "one";
> 
>        case 2:
>            if (throwOnTwo)
>                throw new TwoException();
>            else
>                break "two";
> 
>        case 3:
>             StringMaker sm = new StringMaker();
>             sm.setSeed(System.currentTimeMillis());
>             break sm.randomString();
>     }
> 
> While all of these are likely to be infrequent, telling people "just
> refactor your switch to a chain of if-then-else if you want to do that"
> is going to go over like the proverbial lead balloon.
> 
> So, no to that one.
> 
>>    2/ that we should use the lambda syntax with return, even if the semantics is
>>    different from the lambda semantics.
> 
> Yes, we considered this, and actually thought this was a clever idea for
> a short while.  (General lesson: beware of clever-seeming ideas.)  But,
> among other problems, reusing "return" in this manner is even more of an
> abuse than reusing "break".  It's a credible choice, but it has its own
> problems too.
> 
>> So should we backup and re-use the lambda semantics instead of enhancing break ?
> 
> Pesonally, I think if we're going to stick with switch, the current
> proposal -- which generalizes the existing switch semantics -- is
> staying more true to what switch is.  If we find we have to abandon
> switch and do something else, then I think many more options are on the
> table.
> 
> BTW, I think most people misunderstand the current proposal because its
> usually explained backwards.  So let me explain it forwards, and I think
> it makes more sense this way.
> 
> STEP 1: Extend switch so it can be an expression.  Extend break so it
> can take a value to be yielded from the switch expression.
> 
> This means that everything about statement switches and expression
> switches are the same, except that a statement switch can terminate
> nonlocally and an expression switch can't.  But it is a very
> straightforward extension of the control flow of switch to expressions,
> and that's a plus.  What's ugly about it is that you have to say break a
> lot:
> 
>     int x = switch (y) {
>         case 1: break 2;
>         case 2: break 4;
>         case 3: break 8;
>         default: throw new TooBigException();
>    }
> 
> Which brings us to step two, which is purely a syntactic optimization
> for the very common case where an expression switch arm has no
> statements other than break:
> 
> STEP 2: In a switch expression, allow:
> 
>     case label -> e
> 
> as shorthand for
> 
>     case label: break e
> 
> (much as an expression lambda is a shorthand for a statement lambda.)
> 
> If you explain it the other way, people think that -> is what makes the
> switch an expression switch, and then the break rule seems weirder.

I think part of the confusion comes from the fact that we reuse '->' which is strongly associated to lambdas,
perhaps a way to avoid that is to not reuse the arrow.

When you say expression lambda is a shorthand for statement lambda, nevertheless, both form use the arrow,
again, what if we do not use an arrow for the shorthand case ?

Technically, i do not think we need a symbol at all, but it will be ugly because we also want to have multiple values for the case separated by comma.
So let say we need a symbol but not '->', perhaps ':>' may work ? 

int x = switch (y) {
        case 1 :> 2;
        case 2 :> 4;
        case 3 :> 8;
        default:
            throw new TooBigException();
    };

Rémi


More information about the amber-spec-experts mailing list