Another possible keyword is 'pass'. Rémi
> De: "Brian Goetz" <brian.go...@oracle.com> > À: "amber-spec-experts" <amber-spec-experts@openjdk.java.net> > Envoyé: Dimanche 12 Mai 2019 21:38:38 > Objet: Call for bikeshed -- break replacement in expression switch > As mentioned in the preview mail, we have one more decision to make: the new > spelling of “break value” in expression switches. We have previously discussed > “break-with value”, which everyone seems to like better than “break value”, > but > I think we can, and should, do better. > (Despite the call-for-bikeshed, this is not to reopen every sub-decision — the > 2x2 semantics, the use of ->, the name of the construct — this bikeshed only > has room for one bike.) > There are two primary reasons why we prefer break-with to break. We originally > chose “break value" when we had a more limited palette of options to choose > from (the keyword-resupply ship hadn’t yet docked.) The overloading of break > creates uncomfortable interactions. There is the obvious ambiguity between > “break value” and “break label”; there is also the slightly less obvious > interaction where we cannot permit “break value” inside a loop or statement > switch inside an expression switch. While both of these can be “specified > around”, they create distortions in the spec, which in turn creates complexity > in the user model; these are a sign that we may be pushing something a bit too > far. Further, historically “break” has been a straight transfer of control; > this muddies up what “break” means. > Once we alit on the idea of break-* as a keyword, it seemed immediately more > comfortable to make a new break-derived keyword; this allowed us to undo the > distortions that “break value” introduced, and it immediately felt better. But > I think we can do better still. Here’s what’s making me uncomfortable. > We’ve actually been here before: lambda expressions were the first time we > allowed an expression to contain statements, and while the streamlined case of > “x -> e” didn’t require any control statements, and many lambdas could be > expressed with this form, statement lambdas needed a way to say “stop > executing > the body of this lambda, and yield a value.” We settled — somewhat > uncomfortably — on “return value" for this. > Fast-forward to today, when we’re introducing the second expression form that > can contain statements, and we face the same question: how to indicate “I’m > done, I’m completing normally, here’s my value.” Lambdas provide no help here; > we can’t use “return” here. (Well, we could, but that would be terrible, so > we’re not going to.) Which means we have to solve the problem again, but > differently. That’s already not so great. > Digression: What’s so terrible about “return”, any why is it OK for lambdas > but > not OK for switches? > While we could of course define “return” to mean whatever we want, But, in > imperative languages with the concept of “methods” or “procedures”, including > Java, return has always had a clear meaning: unwind the current call frame, > and > yield the designated value to the caller. Lambda expressions are effectively > method bodies (lambdas are literals for functional interfaces, which are > single > method interfaces), and so return (barely) fits. But switch expressions are > most definitely not methods, and are not associated with call frames. Asking > users to look at the enclosing context when they see a “return” in the middle > of a method, to know whether it returns from the method or merely transfers > control within the method, is a lot to ask. (Yes, I know lambdas ask this as > well; this is why this was an uncomfortable choice, and having made this hole, > I’m not anxious to expand it dramatically. If anything I’d prefer to close it, > but that’s another bikeshed.). > (end digression) > We could surely take “break-with” and move on; it feels sufficiently > “switchy”. > But let’s look ahead a little bit. We’ve now confronted the same problem > twice: > an expression form that, in a minority use case, needed a way to express “stop > computing this expression, because I’m done, and here’s its value.” (And, > unfortunately, we have two different syntactic ways to express the same basic > concept.) Let’s call these “structured expressions.” > We have two structured expression forms, and of the three numbers in computer > science, “two” is not one of them. Which suggests we are going to face this > problem again some day — whether it be “block expressions”, or “if > expressions”, or “let expressions”, or “try expressions”, or whatever. (NB: > this call-for-bikeshed most definitely does not extend to “why not just do > generalized block expressions”, so please don’t go there. That said, you could > treat this discussion as “if Java had block expressions, what might they look > like?” But we’re focusing on the content of the block, not how the block is > framed.) > Let’s say for sake of argument that we might someway want to extend ternary > expressions to support the same kind of “restricted block expressions” as > expression switches. (This is just an example for purposes of illustration, > let’s not get derailed on “but you should use an ‘if’ statement for that"). > String s = (foo != null) > ? s > : { > println(“null again at line” + __LINE__); > break-with “null”; > }; > Such an expression needs a way to say “I’m done, here’s my value”, just as > lambda and switch did before it. Clearly “return” is not the right thing here > any more than it is for switches. And I don’t think “break-with” is all that > great here either! It’s not terrible, but outside of a loop or switch, it > starts to feel kind of forced. And it would be terrible to solve this problem > twice with one-time solutions, and have no general story, and then have to > come > up with YET ANOTHER way of expressing the same basic concept. So regardless of > what we expect for future expression forms, let’s examine what our options are > that are not tied to call frames (return) or direct transfer of control > (switches and loops.). > Looking at what other languages have done here, there are a few broad > directions: > - A statement like “break-with v”, indicating that the enclosing structured > expression is completing normally with the provided value. > - An operator that serves the same purpose, such as “-> e”. > - Assigning to some magic variable (this is how Pascal indicates the return > value of a function). > - Treating the last expression in the block as the result. > I think we can dispatch all but the first relatively easily: > - We don’t use operators for “return”, we use a keyword; this would be both a > gratuitous departure, as well as too easy to miss. > - Switch expressions don’t have names, and even if we assigned to “switch”, it > wouldn’t be obvious that we were actually terminating execution of the block. > - Everywhere else in the language (such as method bodies), you are free to > yield > up a value from the middle of the block, perhaps from within a control > construct like a loop; restricting the RHS of case blocks to put their result > last would be a significant new restriction, and would limit the ability to > refactor to/from methods. And further, the convention of putting the result > last, while a fine one for a language that is “expressions all the way down”, > would likely be too subtle a cue in Java. > So, we want a keyword (or contextual keyword.). In some hallway brainstorming, > candidates that emerged include yield, produce, offer, offer-up, result, > value-break, yield-value, provide, resulting-in, break-with, resulting, > yielding, put, give, giving, ... > (Also to keep in mind: remember we’re dealing with a minority case; most of > the > time, there’ll just be an expression on the RHS.) > TL;DR: I think we might come to regret break-* just as we did with return — > because it won’t scale to future demands we place on it, and having *three* > ways to say basically the same thing in three different contexts would be > embarrassing. I would like to see if we can do better. > Of the options listed here, I have a favorite: yield. (This is one of the > terms > we’ve actually be using all along when describing this feature in english.) > There is one obvious objection to “yield”, which I’d like to preemptively > address: that in some languages (though not in Java, except for the > infrequently-used Thread.yield()), it is associated with concurrency > primitives, such as generators. (This was the objection raised when yield was > proposed in the context of lambdas.). But, these association are not grounded > in existing Java constructs (and, the progress of Loom suggests that > constructs > like async/await are not coming to Java, and even if we wanted language > support > for generators, there are ample other ways to say it.) > [ http://dictionary.com/ | Dictionary.com ] lists the following meanings for > yield: > verb (used with object) > - to give forth or produce by a natural process or in return for cultivation: > - to produce or furnish (payment, profit, or interest): > - to give up, as to superior power or authority: > - to give up or over; relinquish or resign: > - to give as due or required: > - to cause; give rise to: > verb (used without object) > - to give a return, as for labor expended; produce; bear. > - to surrender or submit, as to superior power: > - to give way to influence, entreaty, argument, or the like: > - to give place or precedence (usually followed by to): > - to give way to force, pressure, etc., so as to move, bend, collapse, or the > like: > These are mostly consistent with the use of “yield” as proposed here. > One more thing to bear in mind: there is an ordering to abrupt completion > mechanisms, as to how far away they can transfer control: > - yield: can unwind only the innermost yieldable expression > - break/continue: can unwind multiple control constructs (for, while, switch), > but stays within the method > - return: unwinds exactly one method > - throw: unwinds one or more methods > - System.exit: unwinds the whole VM > Bikeshed is open (but remember the bounds of this bikeshed are limited; we’re > talking purely about the syntax of a “stop executing this block and yield a > value to the enclosing context” — and time is ticking.)