Continue in switch

Remi Forax forax at
Tue May 8 21:37:16 UTC 2018

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


> De: "John Rose" <john.r.rose at>
> À: "Brian Goetz" <brian.goetz at>
> Cc: "amber-spec-experts" <amber-spec-experts at>
> 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.goetz at |
> brian.goetz at ] > 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
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <>

More information about the amber-spec-experts mailing list