----- Mail original ----- > De: "Brian Goetz" <brian.go...@oracle.com> > À: "Remi Forax" <fo...@univ-mlv.fr>, "amber-spec-experts" > <amber-spec-experts@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