We can twist the semantics of continue or decide to go with another (local) keyword which i think is a better idea here.
The syntax will be keyword; which is not a valid syntax for a local variable, so any identifier can be used. Like var, i also think we should choose a name which is not a valid name for a local variable if you follow the coding convention, so by example a name composed of two words with no camel case. I propose nextcase; but i'm sure people will find a better alternative name. cheers, Rémi > De: "John Rose" <john.r.r...@oracle.com> > À: "Brian Goetz" <brian.go...@oracle.com> > Cc: "amber-spec-experts" <amber-spec-experts@openjdk.java.net> > Envoyé: Mardi 8 Mai 2018 22:31:12 > Objet: Re: Continue in switch > On May 8, 2018, at 12:31 PM, Brian Goetz < [ mailto:brian.go...@oracle.com | > brian.go...@oracle.com ] > wrote: >> If continue is the right notion, our choice is essentially between: >> - drive towards continue in switch working like it does in everything else, >> and >> deal with ambiguities (switch in loop) as they come up; >> - drive towards something that looks sufficiently different from "naked" >> continue (continue with label, "continue switch") in switches, and accept >> there >> will be a permanent seam (in switch you do it this way, in loops, this other >> way.) > (Cards on table: I'm on Team `continue switch;` and $0.02 follows.) > The permanent seam doesn't bother me very much, for the following > explainable reason: Switch is not a proper loop, although it is a > continuable statement. If you want to continue a continuable > statement that isn't a loop, you have to be specific. (And you > should be specific anyway if your code is deeply nested.) > Classic Java loops while/for/do-while are (usually) not statically > bounded. Depending on their logic they can run an arbitrary > number of times. > Now, by saying "continue" in a switch, we are ascribing it a loopish > nature. And this is true, because a switch is (in our new theory) > a _decision chain_, that is a finite, sequence of statically defined > predicates which are tested in order until one matches. The number > of predicates is arbitrary (like a loop) but they are listed statically > (unlike a loop). > In both loops and decision chains there is a well-defined and very > useful control flow operation, which is "continue to the next step". > The next step of the loop is to run the iteration and execute the > loop body again. The next step of the decision chain is to abandon > the current predicate and test the next one. > The "continue" concept fits the bill for both. But compatibility says > a bare "continue" must go to a proper loop, not a decision chain. > Thus, bare continue always reaches the enclosing proper loop, > but "continue switch" or "continue L" (L labeling the switch) > reaches the enclosing switch, because although switches are > not proper loops, they are loopish, they are continuable even > if they cannot run forever like a loop. > Explained this way, the "seam" Brian is referring to is an artifact, > not of history, but of the distinction between proper loops and > other continuable ("loopish") constructs. Personally I'd be fine > with this seam as a permanent thing. > The seam can be reduced also, and I think that is what Brian > is aiming at. Bare "continue" in an expression switch will always be > unambiguous, since it *cannot* reach an enclosing loop (no branches > out from an expression.) Sailing yet more closely to the wind: Bare > "continue" in a switch *not* nested in a loop is also unambiguous, > since there's no proper loop to reach. > Brian, are you thinking that bare continue, inside switch, *inside loop*, > is an *ambiguity error*? That would be worth warning about about: > Today's correct code would become an error tomorrow: > for (;;) { > switch (x) { > case 0: > continue; // Error/warning: ambiguous unlabeled continue > } > } > The message could say "unlabeled continue is ambiguous when > nested in both switch and proper loop, repair by saying either > 'continue switch' or 'continue for', or use a label." > In that case, the warnings could be sent even after feature adoption. > Eventually when the warnings turn to errors, no code changes > semantics, but some code breaks. Or make it be a warning forever. > OK, now for some "decision chain theory". > Besides switches, decision chains have two other forms which are > worth contemplating, as elucidating the essential structure in another > surface form, and also as a possible refactoring target. > switch (x) { > case P1 -> S1; // suppressing legacy fallthrough for simplicity > case P2 -> S2; > … > } > if (x matches P1) S1; > else if (x matches P2) S2; > else … > for (Function<XType, Optional<YType>> casef : List.of( > x -> x matches P1 ? Optional.of(S1) : Optional.none(), > x -> x matches P2 ? Optional.of(S2) : Optional.none() > )) { > var y = casef.apply(x); > if (!y.isPresent()) continue; > result = y.get(); > break; > } > The third form seems exotic but it is a coding pattern some > of us have surely used for decision chains, test lists, and > on similar occasions. (I have!) > The continue keyword is native in the third form, and corresponds > exactly to the proposed continue [switch] form for the first form. > OK, now I'm going to push farther, by your leave, with a thought > experiment exploring and extending the correspondence between > the first two forms of decision chain, switch and if/else. > The second form is of course a far more common refactoring of > decision chains; in fact one of the motivations of pattern-switch > is to refactor many existing if/else decision chains into easier-to-read > switches. Here's an example: > if (x matches Plus(0.0, var a)) { > res = a; > } else if (x matches Plus(var a, 0.0)) { > res = a; > } else { > res = x; > } > This simplifies to a switch-based decision chain: > switch (x) { > case Plus(0.0, var a) -> res = a; > case Plus(var a, 0.0) -> res = a; > default -> res = x; > } > Here's the odd part: The close duality between if and switch forms > suggests that we should also consider "continue if", as a form which > means "find the innermost enclosing 'if' with a continuation point > and branch to it". What on earth is a continuation point of an 'if'? > That's easy, it's spelled "else". In other words, if/else (not just > if w/o else) is loopish too. (And "if" without an "else" gets passed > by from "continue" since there is no continuation point.) > Here's the same example, but enhanced with guards (isNan): > switch (x) { > case Plus(0.0, var a): > if (a.isNan()) continue switch; > res = a; > break; > case Plus(var a, 0.0): > if (a.isNan()) continue switch; > res = a; > break; > default: > res = x; > } > What's the equivalent if/else decision chain, with the same guards? > if (x matches Plus(0.0, var a) && !a.isNan()) { > res = a; > } else if (x matches Plus(var a, 0.0) && !a.isNan()) { > res = a; > } else { > res = x; > } > But this one pushes the guards to one side, making the > basic structure easier to read (in some cases, not all!): > if (x matches Plus(0.0, var a)) { > if (a.isNan()) continue if; > res = a; > } else if (x matches Plus(var a, 0.0)) { > if (a.isNan()) continue if; > res = a; > } else { > res = x; > } > How often have you added a complicated "&& !foo" rider expression > to an otherwise clear "if/else" chain, just to push control forward towards > the next "else" which miight handle your marginal "foo" condition? > I have, many times. I think "continue if" would have been helpful. > (Note that "break if" is slightly useful too, if you just want to execute > a localized action for some marginal condition and be done. Today > you need to nest your main action equally with the marginal action, > putting an if/else inside the if/else. That's not too bad, but we might > sometime might prefer the option of making the marginal case be > an asymmetrical add-on to the main flow of logic.) > — John