# Adding explicit intent for SWITCH/CASE fall through?

- Thread: https://externals.io/message/107568
- Original archive: https://news-web.php.net/php.internals/107568
- Started by Mike Schinkel on 2019-10-17T20:54:51+00:00
- Messages: 15
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #107568 — Mike Schinkel — 2019-10-17T20:54:51+00:00

URL: https://externals.io/message/107568#107568

Hi All,

Before creating an RFC I wanted to get reactions to the idea of adding FALLTHROUGH option to SWITCH/CASE for when the developer explicitly want logic to fall through to the next case and does not want to use a BREAK.

My simples motivation for this feature is that my IDE (PhpStorm) always flags CASE statements w/o BREAKs because it cannot know when I intend for the logic to fallthrough and not break.  If there was an optional FALLTHROUGH then my IDE could flag any CASE statements that do not have a FALLTHROUGH or BREAK — which would indicate an error of my intent — and avoid flagging all the situations where I intentionally want it to fall through.

Beyond that, this might also be useful for other static analysis tools such as PhpStan.
Ust 
Additionally it could be added in 8.0 and then in 8.1 flagged with a warning when a CASE does not have one for the two, but only if people don't object to this. While I know some on this list feel strongly that warnings must come with to future plans to generate errors I would personally be 100% okay if it indefinitely generated only a warning.

In summary I want a mechanism to be allow me to explicitly indicate my intent with respect to SELECT/CASE statements.  What do you think? Is this worthy of an RFC, or is there some reason a majority would object to such an addition?

Thanks in advance.

-Mike

---

## #107569 — Mark Randall — 2019-10-17T21:42:34+00:00

URL: https://externals.io/message/107568#107569 · In reply to: #107568

> Additionally it could be added in 8.0 and then in 8.1 flagged with a warning when a CASE does not have one for the two, but only if people don't object to this. While I know some on this list feel strongly that warnings must come with to future plans to generate errors I would personally be 100% okay if it indefinitely generated only a warning.

Would you put this at switch level, or case level?

Unless your plan is to redefine how switch works by default, which would 
be quite ambitious, I'm not sure it makes a great deal of sense to add a 
token that would effectively no-op in all circumstances.

It sounds like a job for a static analysis comment:

/** @DisableSwitchStatementFallthroughWarning */
switch ($x) {
   case 1:
     $x = doSomething();

   case 2:
     doLaLaLaLa();
     break;

   default:
     doTralala();
}

--
Mark Randall

---

## #107570 — Mike Schinkel — 2019-10-17T22:07:22+00:00

URL: https://externals.io/message/107568#107570

At the case level, not the switch level.

Here is the code that I was working on that caused me to finally send this message.


switch ( $new_name ) {
   case 'portal_id':
   case 'portalid':
      $new_name = 'portalId';
      break;
   case 'form_id':
   case 'formid':
      $new_name = 'formId';
      break;
   case 'educationtype': 
      $update = false;
      fallthrough;
   case 'education':
      $new_name = 'educationType';
      if ( EducationTypes::is_edu_type_slug( $value ) ) {
         $new_value = EducationTypes\Names::get( $value );
      }
      break;
   default:
      $update = false;
      break;
}

(Note the code is from an iterative refactoring process where I will eventually get rid of this specific code but in the short term I am trying to unify all the terms into a single list rather than have a bunch of different names in the code for the same thing. When iterative refactoring my emphasis is understanding the logic and on on unifying the code and not on what is the best architecture.)

> It sounds like a job for a static analysis comment:
> 
> /** @DisableSwitchStatementFallthroughWarning */

Interesting. That feels more like static analysis tools use the only tool they have — comments — since they can't change PHP, and not a good model for language evolution.

My reaction is it feels rather inelegant. It would be a heck of a lot more to type and a good bit harder to read.  In my perfect world it would be part of the language, not just a commenting convention. 

Is there a a standardized list of these for PHP somewhere on php.net?  I googled and did not find any such list; maybe I am missing it? 

I doubt we would want an option in the future for PHP to generate a warning when this type of comment is missing?  Key to this request is that PHP also generates a warning when warnings are turned on during development.

Also, when reading code I tend to have "comment blindness" similar to how people have "ad blindness" when browsing the web. Since comments are typically not code and are often not maintained I don't trust them so only read comments when the code is hard to decipher. In this case if I saw a missing break I would assume the person intended it and might not realize there is a comment indicating it.  But YMMV.  


> a token that would effectively no-op in all circumstances.

Is it really a no-op?  I envisioned is a jump to the next case.

But I also saw that it was small enough scope I could probably use it to learn how to author a patch for PHP.

BTW, GoLang has exactly what I am asking about: 

	https://github.com/golang/go/wiki/Switch#fall-through


-Mike


> 
> 
> 
> > […]
> 
> Would you put this at switch level, or case level?
> 
> Unless your plan is to redefine how switch works by default, which would be quite ambitious, I'm not sure it makes a great deal of sense to add a token that would effectively no-op in all circumstances.
> 
> It sounds like a job for a static analysis comment:
> 
> /** @DisableSwitchStatementFallthroughWarning */
> switch ($x) {
>  case 1:
>    $x = doSomething();
> 
>  case 2:
>    doLaLaLaLa();
>    break;
> 
>  default:
>    doTralala();
> }
> 
> --
> Mark Randall

---

## #107571 — Bishop Bettini — 2019-10-18T03:14:09+00:00

URL: https://externals.io/message/107568#107571 · In reply to: #107568

> Before creating an RFC I wanted to get reactions to the idea of adding
> FALLTHROUGH option to SWITCH/CASE for when the developer explicitly want
> logic to fall through to the next case and does not want to use a BREAK.
>
> My simples motivation for this feature is that my IDE (PhpStorm) always
> flags CASE statements w/o BREAKs because it cannot know when I intend for
> the logic to fallthrough and not break.  If there was an optional
> FALLTHROUGH then my IDE could flag any CASE statements that do not have a
> FALLTHROUGH or BREAK — which would indicate an error of my intent — and
> avoid flagging all the situations where I intentionally want it to fall
> through.
>
> Beyond that, this might also be useful for other static analysis tools
> such as PhpStan.
> Ust
> Additionally it could be added in 8.0 and then in 8.1 flagged with a
> warning when a CASE does not have one for the two, but only if people don't
> object to this. While I know some on this list feel strongly that warnings
> must come with to future plans to generate errors I would personally be
> 100% okay if it indefinitely generated only a warning.
>
> In summary I want a mechanism to be allow me to explicitly indicate my
> intent with respect to SELECT/CASE statements.  What do you think? Is this
> worthy of an RFC, or is there some reason a majority would object to such
> an addition?
>

+1. It's 100% opt-in. People can keep using implicit fall-through, their
own /* fallthrough */ comments, or the new token. There's virtually no
overhead in the compile phase and it doesn't mess with the jump table
optimizations. There's precedent for this desire in PHP static analyzers
[1] as well as other major projects: eg, the Linux Foundation just
completed a 2 year project to remove implicit fall-through in the Linux
kernel [2] (*).

That said, some questions:

Do you envision this token accepting an optional argument, as break does,
to fall-through multiple nesting levels? Eg:

<?php
$x = $y = $z = 1;
switch ($x) {
case 1:
    switch ($y) {
    case 1:
        switch ($z) {
        case 1: fallthrough 3;
        case 2: echo 'z2';
        }
    }
    break;
case 2: echo 'x2'; break;
}
?>

What do you envision the result of indicating fall-through to no subsequent
case? Eg:

<?php
switch ($x) {
case 1: fallthrough;
}
?>

Would a "pragma" (of sorts) be a part of the concept?

<?php declare(strict_break=1);
switch ($x) {
case 1: echo 'x1'; // ImplicitBreakError thrown here
case 2: echo 'x2';
}
?>

[1]:https://github.com/phan/phan/issues/2550
[2]:https://lwn.net/Articles/794944/

(*) Fun trivia: PHP is mentioned in that LWN article about naming
conventions.

---

## #107572 — Markus Fischer — 2019-10-18T08:45:17+00:00

URL: https://externals.io/message/107568#107572 · In reply to: #107570

>     case 'educationtype':
>        $update = false;
>        fallthrough;

I was about to suggest `continue`, alas we know that would clash :-)

Suggestion: `next;` instead?

- Markus

---

## #107573 — Rowan Tommins — 2019-10-18T08:54:15+00:00

URL: https://externals.io/message/107568#107573 · In reply to: #107571

Hi Bishop,

I'm not the proposer, but would like to answer your questions anyway.




> Do you envision this token accepting an optional argument, as break does,
> to fall-through multiple nesting levels? Eg:
>
> <?php
> $x = $y = $z = 1;
> switch ($x) {
> case 1:
>     switch ($y) {
>     case 1:
>         switch ($z) {
>         case 1: fallthrough 3;
>         case 2: echo 'z2';
>         }
>     }
>     break;
> case 2: echo 'x2'; break;
> }
> ?>
>


I think we should keep it simple - we can always add more features later if
a real need reveals itself.

I note that the Go version linked to explicitly forbids the use of
"fallthrough" in a conditional, and a multi-level fallthrough is
effectively the same thing: the control flow in your example is something
like if ( $y==1 && $z == 1 ) { fallthrough; } else { break; } I would have
thought that by the time you've got nested switch statements with
conditional fallthrough on multiple levels, the code is going to be very
hard to reason about, so unless there's a key use case, I'd leave the
complexity out of the language.

There might be use cases for single-level conditional fallthrough, but I'd
lean towards defining it as Go has: as a marker at the end of the case
block only. By far the most common use of it I've seen is like Mike's:

case x:
   additional pre-processing
   fallthrough
case y:
   shared processing
   break




> What do you envision the result of indicating fall-through to no subsequent
> case? Eg:
>
> <?php
> switch ($x) {
> case 1: fallthrough;
> }
>


I think it would be perfectly fine for this to do nothing. Currently you
can write both

switch ($x) {
case 1:
}

and

switch ($x) {
case 1: break;
}



In general, I really like this idea; I've always wished switch worked this
way.

Regards,
-- 
Rowan Tommins
[IMSoP]

---

## #107575 — Mike Schinkel — 2019-10-18T18:51:34+00:00

URL: https://externals.io/message/107568#107575 · In reply to: #107571

> 
> 
> +1. It's 100% opt-in. People can keep using implicit fall-through, their own /* fallthrough */ comments, or the new token. There's virtually no overhead in the compile phase and it doesn't mess with the jump table optimizations. There's precedent for this desire in PHP static analyzers [1] as well as other major projects: eg, the Linux Foundation just completed a 2 year project to remove implicit fall-through in the Linux kernel [2] (*).
> 
> That said, some questions:

Hi Bishop,

Thank you for the questions.

> Do you envision this token accepting an optional argument, as break does, to fall-through multiple nesting levels? Eg:

No.  I had not envisioned anything more than a single statement that would indicate to PHP and other tools that a developer intends to _not_ use a break. 

What you suggest had not occurred to me, and is an interesting idea. But I think I would prefer — like Rowan Tommins argued — that we should keep it simple.  

Being able to fallthrough many levels would be an extra feature we can already accomplish in other, more explicit ways. I would rather focus on targeting a use-case we cannot currently address, i.e. for PHP itself and other tools to be able to flag lack of an explicit case exiting action.


> What do you envision the result of indicating fall-through to no subsequent case? Eg:
> 
> <?php
> switch ($x) {
> case 1: fallthrough;
> }
> ?>

Since it would have no effect that could be flagged or not flagged as a warning.  

It might be nice to allow it so that refactoring is less likely to result in a warning.


> Would a "pragma" (of sorts) be a part of the concept?
> 
> <?php declare(strict_break=1);
> switch ($x) {
> case 1: echo 'x1'; // ImplicitBreakError thrown here
> case 2: echo 'x2';
> }
> ?>

Yes, but recent discussions on this list lamented the concern that we could end up with tens if not hundreds of pragmas, and I concur that would be no fun.  

So how we would indicate is an open question PHP should answer before adding a pragma for fallthrough. As an aside, I would be excited to see that discussion start in earnest.

Also, I am sure you remember that Nikita proposed an idea loosely described as "Editions" and that might be the way to go. Imagine the following:

<?php declare(edition=2020);
switch ($x) {
case 1: echo 'x1'; // ImplicitBreakError thrown here
case 2: echo 'x2';
}

Or another approach could just be version specific:

<?php declare(strict[version]=php8);
switch ($x) {
case 1: echo 'x1'; // ImplicitBreakError thrown here
case 2: echo 'x2';
}

For these though, the devil would be in the details.

-Mike

---

## #107576 — Mike Schinkel — 2019-10-18T18:57:50+00:00

URL: https://externals.io/message/107568#107576 · In reply to: #107572

> 
> 
> 
> > […]
> 
> I was about to suggest `continue`, alas we know that would clash :-)
> 
> Suggestion: `next;` instead?

I am agnostic about which word is used, so I would open up for suggestions if others think there is a better word than `fallthrough`.

As far as I care, it could be any of the following[1] as long as the functionality was the same (this is me being a little tongue-in-cheek here):

- proceed
- carry_on
- persevere
- keep_going
- go_ahead 
- advance
- go_forward
- keep_on
- furthermore

-Mike
P.S. Props to powerthesaurus.com!

[1] https://www.powerthesaurus.org/continue/synonyms <https://www.powerthesaurus.org/continue/synonyms

---

## #107578 — A.L.E.C — 2019-10-19T07:05:59+00:00

URL: https://externals.io/message/107568#107578 · In reply to: #107576

> > […]
> 
> I am agnostic about which word is used, so I would open up for suggestions if others think there is a better word than `fallthrough`.
> 
> As far as I care, it could be any of the following[1] as long as the functionality was the same (this is me being a little tongue-in-cheek here):
> 
> - proceed
> - carry_on
> - persevere
> - keep_going
> - go_ahead 
> - advance
> - go_forward
> - keep_on
> - furthermore

Or "pass", but very good candidate for consistency should be "continue". Of course that
would be a big BC break.

Imo, this would make more sense if fallthrough did something more, e.g. allowing

case X:
	if (something) {
		fallthrough;
        }
	something-else;
	break;
case Y: ....

Going this way we could imagine that `fallthrough N` could allow skipping N following
`case`s and `fallthrough default` jumping to the default section. Then, don't we need a
way to jump outside of the whole switch statement? Ah, there's `goto` already. So, maybe
extend `goto` somehow?

I'm just throwing some ideas to consider, I don't pretend they are good. Adding a no-op
keyword does not make much sense to me. It might be not useful enough to justify a BC
break. You could call it "noop" as well.

-- 
Aleksander 'A.L.E.C' Machniak
Kolab Groupware Developer         [http://kolab.org]
Roundcube Webmail Developer   [http://roundcube.net]
----------------------------------------------------
PGP: 19359DC1 # Blog: https://kolabian.wordpress.com

---

## #107579 — Kris Craig — 2019-10-19T07:21:57+00:00

URL: https://externals.io/message/107568#107579 · In reply to: #107578

> 
>
> Imo, this would make more sense if fallthrough did something more, e.g.
> allowing
>
> case X:
>         if (something) {
>                 fallthrough;
>         }
>         something-else;
>         break;
> case Y: ....
>
>
+1

If we're going to do this, let's take the opportunity to make it even more
useful.  I love the idea of being able to explicitly define fallthrough
points in a case.

I agree that "continue" is the logically ideal solution, but the BC
breakage negates that.  So I'd have to go with "next", as it's both concise
and descriptive.

--Kris

---

## #107582 — Mike Schinkel — 2019-10-20T00:39:38+00:00

URL: https://externals.io/message/107568#107582 · In reply to: #107578

> 
> Imo, this would make more sense if fallthrough did something more, e.g. allowing
> 
> case X:
> 	if (something) {
> 		fallthrough;
>        }
> 	something-else;
> 	break;
> case Y: ....

Interesting. 

What would you expect this to do?  It is not intuitively obvious to me.


> Going this way we could imagine that `fallthrough N` could allow skipping N following
> `case`s

While I can see that as possible, I cannot think of any use-cases where I would even want to use it. Can you?

Either way, I doubt I would never use it as IMO it could make for some very fragile code.  


> and `fallthrough default` jumping to the default section.

Now I do like this, because it does not seem fragile to me and I could see it having some use-cases.


> Then, don't we need a way to jump outside of the whole switch statement? Ah, there's `goto` already. So, maybe extend `goto` somehow?

Is that not what `break` is for?

> Adding a no-op keyword does not make much sense to me.

There are many no-op keywords already in PHP, such as typehints; they provide information to the PHP so it knows when to throw warnings and errors.

The fact a potential feature is a no-op does not discredit it for me; instead I focus on the benefits the proposed feature can provide. 

In this case the benefits would be to alerting developer when they accidentally omit instructions to PHP of their intentions. And that seems to me to be something (almost?) everyone would want to see embraced?  Clearly* PHPStan and many Linux developers would like the same[1][2].


> It might be not useful enough to justify a BC break. 

True, that is a concern.

Not yet having experience working on PHP's parser I do not know how it is configured nor what about the design of PHP requires keywords unable to be used as constants, class names, function or method names. I know this is a tangent but that seems like a requirement designed to simplify the parser maybe, and not because of any logical requirement. So I assume whatever word was used for this would also have to be a reserved keyword?  Or not?

Can someone who knows why the parser requires reserve words speak to why? 

If it would have to be a BC break, then maybe we could overload break with `BREAK NEXT` instead of `FALLTHROUGH` to achieve the same goal?  Or `CONTINUE NEXT`?

I will say the term `FALLTHROUGH` is used in GoLang and the GCC compiler[2] so it might be the best for familiarity reasons, but BC might override that concern.

Does anyone know how to quickly scan the top PHP projects to see how many would break if `FALLTHROUGH` were used? I know I could write a program to do it, but I have so many other programs to write...

-Mike

* Props to Bishop Bettini for these links
[1] https://github.com/phan/phan/issues/2550 <https://github.com/phan/phan/issues/2550>
[2] https://lwn.net/Articles/794944/ <https://lwn.net/Articles/794944/

---

## #107583 — Mike Schinkel — 2019-10-20T00:44:09+00:00

URL: https://externals.io/message/107568#107583 · In reply to: #107579

> 
> If we're going to do this, let's take the opportunity to make it even more
> useful.  

Assuming this idea truly does have momentum, I hope we do not get so focused on the `perfect` that we postpone the `good` indefinitely. There is always next version...

> I love the idea of being able to explicitly define fallthrough
> points in a case.

Can you elaborate on this, with use-cases and syntax examples, please?

> I agree that "continue" is the logically ideal solution, but the BC
> breakage negates that.  So I'd have to go with "next", as it's both concise
> and descriptive.

Given A.L.E.C.'s point about BCy, I think `next` would be much more likely to conflict with code-in-the-wild than `fallthrough.`

That said, if we overload `continue` with an argument of `next`, that might be best of both worlds, e.g. `continue next;`

-Mike

---

## #107584 — A.L.E.C — 2019-10-20T07:01:22+00:00

URL: https://externals.io/message/107568#107584 · In reply to: #107582

> > […]
> 
> Interesting. 
> 
> What would you expect this to do?  It is not intuitively obvious to me.

Directly jump to the next `case` (as `goto` would do).

Also, fallthrough probably shouldn't be just a no-op, it should be jump. Consider this code

case X:
   fallthrough;
   break;
case Y:

It should be clear what would happen in such cases.

> > […]
> 
> Is that not what `break` is for?

Right. I was too much on throwing new ideas that I missed that some are already
implemented ;). The point was that fallthrough with these added functionality mentioned
above would be very close to `goto`. On the other hand:

case X:
   goto next; // or goto case; ?
case Y:

sounds worse than:

case X:
   fallthrough;
case Y:

or

case X:
   pass;
case Y:

> The fact a potential feature is a no-op does not discredit it for me; instead I focus on the benefits the proposed feature can provide. 
> 
> In this case the benefits would be to alerting developer when they accidentally omit instructions to PHP of their intentions. And that seems to me to be something (almost?) everyone would want to see embraced?  Clearly* PHPStan and many Linux developers would like the same[1][2].

Maybe if it was a feature (keyword) that could be useful in other places not only in
switch...

I proposed "pass" because it might have some uses out of switch (nothing comes to my mind,
though right now) and because "fallthrough" is kinda hard word for non-native speakers.

"pass" exists in Python. https://docs.python.org/2.0/ref/pass.html

> > […]

That was my intention, to find more value in a new feature to justify BC break.

-- 
Aleksander 'A.L.E.C' Machniak
Kolab Groupware Developer         [http://kolab.org]
Roundcube Webmail Developer   [http://roundcube.net]
----------------------------------------------------
PGP: 19359DC1 # Blog: https://kolabian.wordpress.com

---

## #107585 — Mike Schinkel — 2019-10-20T07:22:26+00:00

URL: https://externals.io/message/107568#107585 · In reply to: #107584

> 
> > […]
> 
> That was my intention, to find more value in a new feature to justify BC break.

Your point was well taken, which is why I am now suggesting we consider (one of) the following instead of `fallthrough`:

	break next;

	continue next;

-Mike

---

## #107594 — Mike Schinkel — 2019-10-20T21:44:48+00:00

URL: https://externals.io/message/107568#107594

> 
> 
> > […]
> 
> 
> I don't know the full implications in the parser, but at the language level, any constant can technically appear where this keyword would. That is, the following is valid right now:
> 
> const fallthrough=null;
> fallthrough;
> 
> It doesn't do anything, but it's valid because any expression on its own is a valid statement, and a constant on its own is a valid expression.

Thank you for clarifying that.

Still, I wonder if a reserved word really needs to disallow function, method, class and trait names, which are more problematic to me.  I have often wanted to name a class 'List`.  And I have often wanted to name a method `do()`, `continue()`, `end()` and `try()`.  

Seems like a needless limitation thus forcing the use of less appropriate symbol naming.

> Interestingly, that actually makes a single keyword *more* appealing to me, because it means you can get *forwards* compatibility by writing this:
> 
> if ( `PHP_VERSION` < 80000 && ! defined('fallthrough') ) {
>     define('fallthrough', null);
> }

Oh, that is interesting! 

Too bad you can't define a constant to call an initializer method.

-Mike
