Strict switch statements

php.internals

Sara Golemon

8 years ago
Just for casual discussion at this point: https://github.com/php/php-src/pull/3297 switch ($a) { case FOO: // Works exactly as current behavior. break; case == FOO: // Nearly identical, though not using the ZEND_CASE optimization. // Can probably make this equivalent to `case FOO`, but it felt like an interesting direction. break; case === FOO: // Only triggers if `$a === FOO`, no type juggling break; } Love it? Hate it? See obvious flaws? The implementation is just a rushed proof of concept, not something I've labored over, it may well have bugs. Certainly wouldn't target anything earlier than 7.4, if at all. -Sara

Andrey Andreev

8 years ago
Hi, On Thu, Jun 14, 2018 at 7:53 AM, Sara Golemon <pollita@php.net> wrote:
> Just for casual discussion at this point: > https://github.com/php/php-src/pull/3297 > > switch ($a) { > case FOO: > // Works exactly as current behavior. > break; > case == FOO: > // Nearly identical, though not using the ZEND_CASE optimization. > // Can probably make this equivalent to `case FOO`, but it felt > like an interesting direction. > break; > case === FOO: > // Only triggers if `$a === FOO`, no type juggling > break; > } > > Love it? Hate it? See obvious flaws? The implementation is just a > rushed proof of concept, not something I've labored over, it may well > have bugs. Certainly wouldn't target anything earlier than 7.4, if at > all. >
I love it for the === part. Countless times I've had to avoid switch statements because they can't do strict comparisons. Cheers, Andrey.

Nikita Popov

8 years ago
On Thu, Jun 14, 2018 at 6:53 AM, Sara Golemon <pollita@php.net> wrote:
> Just for casual discussion at this point: > https://github.com/php/php-src/pull/3297 > > switch ($a) { > case FOO: > // Works exactly as current behavior. > break; > case == FOO: > // Nearly identical, though not using the ZEND_CASE optimization. > // Can probably make this equivalent to `case FOO`, but it felt > like an interesting direction. > break; > case === FOO: > // Only triggers if `$a === FOO`, no type juggling > break; > } > > Love it? Hate it? See obvious flaws? The implementation is just a > rushed proof of concept, not something I've labored over, it may well > have bugs. Certainly wouldn't target anything earlier than 7.4, if at > all. >
I like the general idea here (switch with strict type comparison), but not super fond of the particular syntax and implementation. I think if people want to use strict matching, they'll quite likely want to have it on all cases. Something like "strict switch ($expr) {}" or "switch strict ($expr) {}" or "switch (strict $expr) {}" or "switch ($expr) strict {}" or "switch ($expr) { strict; }" or whatever would be preferable in that case. Additionally, switch has the issue of fall-through behavior, which is somewhat unexpected and error prone to many people. It might make sense to introduce an entirely new "match" statement that conforms a bit more with how switch-like strictures are implemented nowadays. That is, something like match ($expr) { "foo" => {...}, "bar" | "baz" => {...}, } or similar. This might need some more design work to ensure forward compatibility with potential future algebraic datatypes etc. Nikita

Rowan Collins

8 years ago
On 14 June 2018 at 09:35, Nikita Popov <nikita.ppv@gmail.com> wrote:
> On Thu, Jun 14, 2018 at 6:53 AM, Sara Golemon <pollita@php.net> wrote: > > > Just for casual discussion at this point: > > https://github.com/php/php-src/pull/3297 > > > > switch ($a) { > > case FOO: > > // Works exactly as current behavior. > > break; > > case == FOO: > > // Nearly identical, though not using the ZEND_CASE optimization. > > // Can probably make this equivalent to `case FOO`, but it felt > > like an interesting direction. > > break; > > case === FOO: > > // Only triggers if `$a === FOO`, no type juggling > > break; > > } > > > > Love it? Hate it? See obvious flaws? The implementation is just a > > rushed proof of concept, not something I've labored over, it may well > > have bugs. Certainly wouldn't target anything earlier than 7.4, if at > > all. > > > > I like the general idea here (switch with strict type comparison), but not > super fond of the particular syntax and implementation. > > I think if people want to use strict matching, they'll quite likely want to > have it on all cases. Something like "strict switch ($expr) {}" or "switch > strict ($expr) {}" or "switch (strict $expr) {}" or "switch ($expr) strict > {}" or "switch ($expr) { strict; }" or whatever would be preferable in that > case. >
For ages, I've had an idea along these lines kicking around. Like Nikita, I was assuming that all branches would want strict comparison or none, so was thinking of putting the operator at the top, something like "switch ($expr) use (===)". I figured it could then be extended so the "===" could be substituted for any binary operator; for instance, you could match values into ranges with "switch ($score) use (>=)". That said, I can see an attraction in a form with the operator on the branch, if operators other than "==" and "===" are supported; for the range example, it might be handy to have cases for ">= 50", "> 0", and "=== 0". I prefer reusing "===" in some way over the word "strict", even if no other operators are supported, because "strict" could mean a number of things - "strictly no fall-throughs", for instance - and I think that could cause confusion (people already expect "strict types" to mean more than it does). Regards,
-- Rowan Collins [IMSoP]

Björn Larsson

8 years ago
Den 2018-06-14 kl. 11:21, skrev Rowan Collins:
> On 14 June 2018 at 09:35, Nikita Popov <nikita.ppv@gmail.com> wrote: > >> On Thu, Jun 14, 2018 at 6:53 AM, Sara Golemon <pollita@php.net> wrote: >> >>> Just for casual discussion at this point: >>> https://github.com/php/php-src/pull/3297 >>> >>> switch ($a) { >>> case FOO: >>> // Works exactly as current behavior. >>> break; >>> case == FOO: >>> // Nearly identical, though not using the ZEND_CASE optimization. >>> // Can probably make this equivalent to `case FOO`, but it felt >>> like an interesting direction. >>> break; >>> case === FOO: >>> // Only triggers if `$a === FOO`, no type juggling >>> break; >>> } >>> >>> Love it? Hate it? See obvious flaws? The implementation is just a >>> rushed proof of concept, not something I've labored over, it may well >>> have bugs. Certainly wouldn't target anything earlier than 7.4, if at >>> all. >>> >> I like the general idea here (switch with strict type comparison), but not >> super fond of the particular syntax and implementation. >> >> I think if people want to use strict matching, they'll quite likely want to >> have it on all cases. Something like "strict switch ($expr) {}" or "switch >> strict ($expr) {}" or "switch (strict $expr) {}" or "switch ($expr) strict >> {}" or "switch ($expr) { strict; }" or whatever would be preferable in that >> case. >> > > For ages, I've had an idea along these lines kicking around. Like Nikita, > I was assuming that all branches would want strict comparison or none, so > was thinking of putting the operator at the top, something like "switch > ($expr) use (===)". I figured it could then be extended so the "===" could > be substituted for any binary operator; for instance, you could match > values into ranges with "switch ($score) use (>=)". > > That said, I can see an attraction in a form with the operator on the > branch, if operators other than "==" and "===" are supported; for the range > example, it might be handy to have cases for ">= 50", "> 0", and "=== 0". > > I prefer reusing "===" in some way over the word "strict", even if no other > operators are supported, because "strict" could mean a number of things - > "strictly no fall-throughs", for instance - and I think that could cause > confusion (people already expect "strict types" to mean more than it does). > > Regards,
Yup, I also like this idea very much. Using the === syntax is a clear message on what's it all about. Having the ability to extend it to other operators is also interesting, e.g. !== & !=. Another point is that by keeping switch keyword it would be relatively easy to upgrade legacy code, making it more robust. Of course there is a use for a new keyword like match extending the functionality even more. Maybe we can have both? I'm thinking if one should be able to have like: switch ($a)  {     case === FOO:         break;     case !== BAR:         break; } or: switch ($a) with !== {     case FOO:         break;     case BAR:         break;     default:         break; } or: switch ($a, ===)  {     case FOO:         break;     case BAR:         break; } r//Björn Larsson

Stephen Reay

8 years ago
Apologies - sending again from on-list address. I’m not overly fond of the `case ===` Could it be simply `case` for current behaviour and `strict case` for the new behaviour? I’d argue that while fall through can cause problems it also has legitimate uses. Sent from my iPhone Sent from my iPhone

Christoph Becker

8 years ago
On 14.06.2018 at 10:35, Nikita Popov wrote:
> On Thu, Jun 14, 2018 at 6:53 AM, Sara Golemon <pollita@php.net> wrote: > >> Just for casual discussion at this point: >> https://github.com/php/php-src/pull/3297 >> >> switch ($a) { >> case FOO: >> // Works exactly as current behavior. >> break; >> case == FOO: >> // Nearly identical, though not using the ZEND_CASE optimization. >> // Can probably make this equivalent to `case FOO`, but it felt >> like an interesting direction. >> break; >> case === FOO: >> // Only triggers if `$a === FOO`, no type juggling >> break; >> } > > I like the general idea here (switch with strict type comparison), but not > super fond of the particular syntax and implementation. > > I think if people want to use strict matching, they'll quite likely want to > have it on all cases. […]
ACK. Even the example shows the gotchas with this kind of mix: the final case would never match, or would it (which I would find even more confusing)? Furthermore, I personally don't like switch statements in a higher level programming language, since they feel so low level (optional fall through, and whatever). And there is already the “switch (true)” hack, to make the proposed behavior possible (without optimizations, though, I presume), see <https://3v4l.org/qPauK> and <https://3v4l.org/iSLkW>.
> Additionally, switch has the issue of fall-through behavior, which is > somewhat unexpected and error prone to many people. It might make sense to > introduce an entirely new "match" statement that conforms a bit more with > how switch-like strictures are implemented nowadays. That is, something like > > match ($expr) { > "foo" => {...}, > "bar" | "baz" => {...}, > }
On a quick thought, I like this!
-- Christoph M. Becker

Sara Golemon

8 years ago
On Thu, Jun 14, 2018 at 4:35 AM, Nikita Popov <nikita.ppv@gmail.com> wrote:
> I like the general idea here (switch with strict type comparison), but not > super fond of the particular syntax and implementation. >
No arguments there. What's presented is "best I could come up in the bath". :)
> I think if people want to use strict matching, they'll quite likely want to > have it on all cases. Something like "strict switch ($expr) {}" or "switch > strict ($expr) {}" or "switch (strict $expr) {}" or "switch ($expr) strict > {}" or "switch ($expr) { strict; }" or whatever would be preferable in that > case. >
Agree that it's more likely to be all-or-not within a switch block. If I could step through my thinking in putting it on the case statement however, I applied two starting rules: 1. Avoid adding new reserved symbols/keywords. 2. Try to make it read naturally. I actually did consider Rowan's suggestion `switch (expr) use (===) {}`, but I didn't feel like it satisfied #2 well. Instead, I chose to think of the T_CASE as a placeholder for the switch expression. If you visually substitute the expression where the 'case' is at, then this: switch ($x) { case === 1: case === 2: } Could be read as: switch (...) { $x === 1: $x === 2: } Not saying that's the only route, just walking through how I would imaging it reading to new eyes.
> Additionally, switch has the issue of fall-through behavior, which is > somewhat unexpected and error prone to many people. It might make sense to > introduce an entirely new "match" statement that conforms a bit more with > how switch-like strictures are implemented nowadays. That is, something like > > match ($expr) { > "foo" => {...}, > "bar" | "baz" => {...}, > } > > or similar. This might need some more design work to ensure forward > compatibility with potential future algebraic datatypes etc. >
That's certainly more ambitious, but since we're just casually talking, then let's explore it. I like the idea of a richer syntax for matching that goes beyond simple equality/identicality, but we'll need to think very carefully about interactions (for example, in your example, is `"bar" | "baz"` a bitwise binary OR?) What might default look like here? I guess we still reuse the default keyword. My nit-pick about the "match" keyword is that I (personally, and this is probably minority) think of this like regex related. I'll be honest, I didn't realize the fall-through behavior was a learning curve issue. This block scoping would address that, but I wonder if we could make use of break/continue. The former's meaning being obvious enough, the latter allowing us to either fall through to the next case or possibly continuing evaluating conditionals. 🤔 -Sara

Rowan Collins

8 years ago
On 14 June 2018 at 15:48, Sara Golemon <pollita@php.net> wrote:
> Agree that it's more likely to be all-or-not within a switch block. > If I could step through my thinking in putting it on the case > statement however, I applied two starting rules: > 1. Avoid adding new reserved symbols/keywords. > 2. Try to make it read naturally. > > I actually did consider Rowan's suggestion `switch (expr) use (===) > {}`, but I didn't feel like it satisfied #2 well. >
I always read it in my head as "switch on expression using the === operator". There is a bit of a punctuation pileup, though.
> I'll be honest, I didn't realize the fall-through behavior was a > learning curve issue. This block scoping would address that, but I > wonder if we could make use of break/continue. The former's meaning > being obvious enough, the latter allowing us to either fall through to > the next case or possibly continuing evaluating conditionals.
Yeah, annoyingly "continue" is actually valid in switch statements, as a confusing synonym of "break", because I always thought it would be nice if you had to balance every non-empty case with either "break" or "continue". It's not just the learning curve that's a problem, it's really easy to write subtly broken code with an accidental fall-through. I was just telling a colleague that I've made this mistake before: //Before: no break needed because there's a return switch ( $foo ) { case 1: return true; default: bar(); } //After: should have added a break, but didn't notice until something went wrong switch ( $foo ) { case 1: if ( $something ) { return true; } default: bar(); } I think a lot of people would find a syntax with { ... } blocks much more familiar. One thing to consider is what actually is the "mission statement" of the switch/match/whatever - what makes it "better" than a chain of if-elseif blocks? Meanwhile, someone just posted this on Stack Overflow https://stackoverflow.com/q/50860319/157957 where someone was trying to use <= in a switch statement! Regards,
-- Rowan Collins [IMSoP]

Mathieu Rochette

8 years ago
Sara Golemon – Thu, 14. June 2018 16:50
> On Thu, Jun 14, 2018 at 4:35 AM, Nikita Popov <nikita.ppv@gmail.com> wrote: > > I like the general idea here (switch with strict type comparison), but not > > super fond of the particular syntax and implementation. > > > No arguments there. What's presented is "best I could come up in the bath". :) > > > I think if people want to use strict matching, they'll quite likely want to > > have it on all cases. Something like "strict switch ($expr) {}" or "switch > > strict ($expr) {}" or "switch (strict $expr) {}" or "switch ($expr) strict > > {}" or "switch ($expr) { strict; }" or whatever would be preferable in that > > case. > > > Agree that it's more likely to be all-or-not within a switch block. > If I could step through my thinking in putting it on the case > statement however, I applied two starting rules: > 1. Avoid adding new reserved symbols/keywords. > 2. Try to make it read naturally. > > I actually did consider Rowan's suggestion `switch (expr) use (===) > {}`, but I didn't feel like it satisfied #2 well. > Instead, I chose to think of the T_CASE as a placeholder for the > switch expression. If you visually substitute the expression where > the 'case' is at, then this: > > switch ($x) { > case === 1: > case === 2: > } > > Could be read as: > > switch (...) { > $x === 1: > $x === 2: > } > > Not saying that's the only route, just walking through how I would > imaging it reading to new eyes. > > > Additionally, switch has the issue of fall-through behavior, which is > > somewhat unexpected and error prone to many people. It might make sense to > > introduce an entirely new "match" statement that conforms a bit more with > > how switch-like strictures are implemented nowadays. That is, something like > > > > match ($expr) { > > "foo" => {...}, > > "bar" | "baz" => {...}, > > } > > > > or similar. This might need some more design work to ensure forward > > compatibility with potential future algebraic datatypes etc. > > > That's certainly more ambitious, but since we're just casually > talking, then let's explore it. > > I like the idea of a richer syntax for matching that goes beyond > simple equality/identicality, but we'll need to think very carefully > about interactions (for example, in your example, is `"bar" | "baz"` a > bitwise binary OR?) What might default look like here? I guess we > still reuse the default keyword. My nit-pick about the "match" keyword > is that I (personally, and this is probably minority) think of this > like regex related.
match is also used to destructure things in other language (at least in Rust). I d'like to to that: $a = [1, 2]; match ($a) { [2, $n] => { ... } [$m, $n] => { ... } [$m, $n, $o] => { ... } [$m, $n, $o, ...$next] => { ... } [] => {...} [$m] => {...} $l =>{...} } and I'm probably dreaming but if I could destructure objects it would be awesome: class User { public $id; public $banned; } $user = $repository->getById($id); // with https://github.com/hoaproject/Option // eg: $user = Some(new User($id, $banned)); // or: $user = None() match ($user) { Some:$user=User:{banned => true} => { assert($user instanceof User); /* user is banned */ } Some:User:{name=$name, banned => $banned, role='admin'} => { assert(!$banned) } Some:$user => { assert($user instanceof User); assert(!$user->banned) } None => { /* user not found */ } } It could also be used to match http Request, Json API input, etc.

Theodore Brown

8 years ago
On Thu, Jun 14, 2018 at 4:35 AM, Nikita Popov <nikita.ppv@gmail.com> wrote: > I think if people want to use strict matching, they'll quite likely want to > have it on all cases. Something like "strict switch ($expr) {}" or "switch > strict ($expr) {}" or "switch (strict $expr) {}" or "switch ($expr) strict > {}" or "switch ($expr) { strict; }" or whatever would be preferable in that > case. > > Additionally, switch has the issue of fall-through behavior, which is > somewhat unexpected and error prone to many people. It might make sense to > introduce an entirely new "match" statement that conforms a bit more with > how switch-like strictures are implemented nowadays. That is, something like > > match ($expr) { >     "foo" => {...}, >     "bar" | "baz" => {...}, > } > > or similar. This might need some more design work to ensure forward > compatibility with potential future algebraic datatypes etc. I really like this idea. It's similar to the `match` control flow operator in Rust: https://doc.rust-lang.org/book/second-edition/ch06-02-match.html. One reason I almost never use the `switch` statement in PHP (besides the lack of strict matching) is that it's so verbose. Having to put a `break` keyword after every case to avoid fallthrough means that it almost always requires less code to use `if` statements instead. To avoid confusion with union types, I think I would prefer commas between or conditions instead of a pipe character. Example: ``` match ($expr) { "foo", "bar" => {echo 'expr is "foo" or "bar"';}, true => {echo 'expr is true';}, 1 => {echo 'expr is 1';}, null => {echo 'expr is null';}, false => {echo 'expr is false';}, default => {echo 'expr is something else';}, } ```

Larry Garfield

8 years ago
On Friday, June 15, 2018 9:54:48 AM CDT Theodore Brown wrote:
> On Thu, Jun 14, 2018 at 4:35 AM, Nikita Popov <nikita.ppv@gmail.com> wrote: > > I think if people want to use strict matching, they'll quite likely want > > to > > have it on all cases. Something like "strict switch ($expr) {}" or "switch > > strict ($expr) {}" or "switch (strict $expr) {}" or "switch ($expr) strict > > {}" or "switch ($expr) { strict; }" or whatever would be preferable in > > that > > case. > > > > Additionally, switch has the issue of fall-through behavior, which is > > somewhat unexpected and error prone to many people. It might make sense to > > introduce an entirely new "match" statement that conforms a bit more with > > how switch-like strictures are implemented nowadays. That is, something > > like > > > > match ($expr) { > > > > "foo" => {...}, > > "bar" | "baz" => {...}, > > > > } > > > > or similar. This might need some more design work to ensure forward > > compatibility with potential future algebraic datatypes etc. > > I really like this idea. It's similar to the `match` control flow operator > in Rust: https://doc.rust-lang.org/book/second-edition/ch06-02-match.html. > > One reason I almost never use the `switch` statement in PHP (besides the > lack of strict matching) is that it's so verbose. Having to put a `break` > keyword after every case to avoid fallthrough means that it almost always > requires less code to use `if` statements instead. > > To avoid confusion with union types, I think I would prefer commas between > or conditions instead of a pipe character. Example: > > ``` > match ($expr) { > "foo", "bar" => {echo 'expr is "foo" or "bar"';}, > true => {echo 'expr is true';}, > 1 => {echo 'expr is 1';}, > null => {echo 'expr is null';}, > false => {echo 'expr is false';}, > default => {echo 'expr is something else';}, > } > ```
I'm not fully sold that anything is needed here, but if something is I would also very much favor a substantially more robust match statement a la Rust, Go, et al over some form of "pickiness flag" on the existing switch. Syntax details TBD, but the benefit of a flag on switch seems minimal while the benefit of more robust type/pattern matching is potentially large. That said, however, also bear in mind that "PHP is not $language": One of the big uses of match in Rust, as I understand it, is to force fully exploring the keyspace of an enum. We of course don't have enums so that use case goes away. Given the emphasis on polymorphism in OOP PHP over RTTI, are there enough non-enum, non-RTTI use cases for a robust match statement to justify its inclusion? If so, then I'm down. :-) --Larry Garfield

Unnamed Person

8 years ago
Nikita Popov wrote on 14.06.2018 10:35:
> On Thu, Jun 14, 2018 at 6:53 AM, Sara Golemon <pollita@php.net> wrote: > >> Just for casual discussion at this point: >> https://github.com/php/php-src/pull/3297 >> >> switch ($a) { >> case FOO: >> // Works exactly as current behavior. >> break; >> case == FOO: >> // Nearly identical, though not using the ZEND_CASE optimization. >> // Can probably make this equivalent to `case FOO`, but it felt >> like an interesting direction. >> break; >> case === FOO: >> // Only triggers if `$a === FOO`, no type juggling >> break; >> } >> >> Love it? Hate it? See obvious flaws? The implementation is just a >> rushed proof of concept, not something I've labored over, it may well >> have bugs. Certainly wouldn't target anything earlier than 7.4, if at >> all. >> > > I like the general idea here (switch with strict type comparison), but not > super fond of the particular syntax and implementation. > > I think if people want to use strict matching, they'll quite likely want to > have it on all cases. Something like "strict switch ($expr) {}" or "switch > strict ($expr) {}" or "switch (strict $expr) {}" or "switch ($expr) strict > {}" or "switch ($expr) { strict; }" or whatever would be preferable in that > case. > > Additionally, switch has the issue of fall-through behavior, which is > somewhat unexpected and error prone to many people. It might make sense to > introduce an entirely new "match" statement that conforms a bit more with > how switch-like strictures are implemented nowadays. That is, something like > > match ($expr) { > "foo" => {...}, > "bar" | "baz" => {...}, > } > > or similar. This might need some more design work to ensure forward > compatibility with potential future algebraic datatypes etc. > > Nikita >
for simplicity I would use an extra parameter to have a strict comparison (similar to the extra parameter in in_array()): switch ($a, true) { // strict comparison switch ($a) { // loose comparison Regards Thomas

Sara Golemon

8 years ago
On Thu, Jun 14, 2018 at 11:57 AM, Thomas Bley <mails@thomasbley.de> wrote:
> for simplicity I would use an extra parameter to have a strict comparison (similar to the extra parameter in in_array()): > > switch ($a, true) { // strict comparison > switch ($a) { // loose comparison >
I instinctively recoil from boolean arguments as they tend to be opaque at a glance, but perhaps: switch ($a, ===) {...} Would both be more apparent as to its meaning and leave the door open for other uses. Though at that point, tbqh, I think `switch ($a) use (===) {...}` gives better visual isolation. -Sara

Stas Malyshev

8 years ago
Hi!
> Would both be more apparent as to its meaning and leave the door open > for other uses. Though at that point, tbqh, I think `switch ($a) use > (===) {...}` gives better visual isolation.
I don't think we should reuse the use() thing for third purpose when we're already using it for two. I imagine with new parser logic we should not be as restricted in syntax choices as we've been before? So being a bit more explicit than "use(===)", which would be a bit of a head-scratcher for a casual PHP user. Something like "strict switch" at least gives a person something to ask about - what is "strict switch" exactly? But "use(===)" would be harder to read and harder to look up online.
-- Stas Malyshev smalyshev@gmail.com

Rowan Collins

8 years ago
On 14 June 2018 at 23:15, Stanislav Malyshev <smalyshev@gmail.com> wrote:
> Hi! > > > Would both be more apparent as to its meaning and leave the door open > > for other uses. Though at that point, tbqh, I think `switch ($a) use > > (===) {...}` gives better visual isolation. > > I don't think we should reuse the use() thing for third purpose when > we're already using it for two. I imagine with new parser logic we > should not be as restricted in syntax choices as we've been before? So > being a bit more explicit than "use(===)", which would be a bit of a > head-scratcher for a casual PHP user. Something like "strict switch" at > least gives a person something to ask about - what is "strict switch" > exactly? But "use(===)" would be harder to read and harder to look up > online. >
As I've said before, I think precisely the opposite: === immediately means "strict comparison" to anyone who knows PHP, but "strict switch" could mean any number of restrictions: strict comparisons, no implicit fall-through of cases, no duplicate cases, etc, etc If it's the keyword reuse and punctuation that are an issue, what about just picking a different word, and leaving out the parens: switch ($foo) with === { case 42: blah(); break; case '42': blerg(); break; } Regards,
-- Rowan Collins [IMSoP]

Alice Wonder

8 years ago
On 06/14/2018 08:57 AM, Thomas Bley wrote:
> Nikita Popov wrote on 14.06.2018 10:35: > >> On Thu, Jun 14, 2018 at 6:53 AM, Sara Golemon <pollita@php.net> wrote: >> >>> Just for casual discussion at this point: >>> https://github.com/php/php-src/pull/3297 >>> >>> switch ($a) { >>> case FOO: >>> // Works exactly as current behavior. >>> break; >>> case == FOO: >>> // Nearly identical, though not using the ZEND_CASE optimization. >>> // Can probably make this equivalent to `case FOO`, but it felt >>> like an interesting direction. >>> break; >>> case === FOO: >>> // Only triggers if `$a === FOO`, no type juggling >>> break; >>> } >>> >>> Love it? Hate it? See obvious flaws? The implementation is just a >>> rushed proof of concept, not something I've labored over, it may well >>> have bugs. Certainly wouldn't target anything earlier than 7.4, if at >>> all. >>> >> >> I like the general idea here (switch with strict type comparison), but not >> super fond of the particular syntax and implementation. >> >> I think if people want to use strict matching, they'll quite likely want to >> have it on all cases. Something like "strict switch ($expr) {}" or "switch >> strict ($expr) {}" or "switch (strict $expr) {}" or "switch ($expr) strict >> {}" or "switch ($expr) { strict; }" or whatever would be preferable in that >> case. >> >> Additionally, switch has the issue of fall-through behavior, which is >> somewhat unexpected and error prone to many people. It might make sense to >> introduce an entirely new "match" statement that conforms a bit more with >> how switch-like strictures are implemented nowadays. That is, something like >> >> match ($expr) { >> "foo" => {...}, >> "bar" | "baz" => {...}, >> } >> >> or similar. This might need some more design work to ensure forward >> compatibility with potential future algebraic datatypes etc. >> >> Nikita >> > > for simplicity I would use an extra parameter to have a strict comparison (similar to the extra parameter in in_array()): > > switch ($a, true) { // strict comparison > switch ($a) { // loose comparison > > Regards > Thomas >
Should declare(strict_types = 1) do that? I haven't tried, but I would think it should.

Rowan Collins

8 years ago
On 14 June 2018 at 17:16, Alice Wonder <alice@librelamp.com> wrote:
> > Should declare(strict_types = 1) do that? > > I haven't tried, but I would think it should.
No, it doesn't, and shouldn't. "strict_types" actually means "non_coercive_scalar_type_hints"; it's a very specific feature, controlling a specific set of situations, not a catch-all "strict mode" for anything type-related. I suppose we could have a new directive that magically changed the default for the "strict" parameter of array_search, et al. But if that converted switch, would it also convert == itself? And then would we need a new syntax for "opting out" and using the loose comparison? Would the resulting confusion of people not seeing which mode a file was in be worth it? This is exactly why I think the word "strict" should be avoided at all costs; it's just far too ambiguous. Regards,
-- Rowan Collins [IMSoP]

Chase Peeler

8 years ago
On Thu, Jun 14, 2018 at 12:45 PM Rowan Collins <rowan.collins@gmail.com> wrote:
> On 14 June 2018 at 17:16, Alice Wonder <alice@librelamp.com> wrote: > > > > > Should declare(strict_types = 1) do that? > > > > I haven't tried, but I would think it should. > > > > No, it doesn't, and shouldn't. "strict_types" actually means > "non_coercive_scalar_type_hints"; it's a very specific feature, controlling > a specific set of situations, not a catch-all "strict mode" for anything > type-related. > > I suppose we could have a new directive that magically changed the default > for the "strict" parameter of array_search, et al. But if that converted > switch, would it also convert == itself? And then would we need a new > syntax for "opting out" and using the loose comparison? Would the resulting > confusion of people not seeing which mode a file was in be worth it? > > This is exactly why I think the word "strict" should be avoided at all > costs; it's just far too ambiguous. > > Regards, > -- > Rowan Collins > [IMSoP] >
Here's an idea, that leaves the flexibility to use strict comparisons on a per case basis, but doesn't use the === syntax, which I don't like either. switch($a){ case true: //will match true, 1, etc... break; strict case false: //will not match anything except boolean FALSE //other stuff break; case false: //will match 0, null, etc.... break; } You could expand this further with a second parameter to the switch, as someone proposed above, that would put it in "strict" mode, and, allow a keyword to change things back to non-strict as needed: switch($a,true){ loose case true: //will match true, 1, etc... break; case false: //will not match anything except boolean FALSE //other stuff break; loose case false: //will match 0, null, etc.... break; } And, if it's in strict mode, you can still specify the strict keyword, and if it's in non-strict mode, you can still specify the loose keyword. Shouldn't even have to make them reserved words either, since they only have meaning inside a switch statement, when immediately before the word "case"
-- -- Chase chasepeeler@gmail.com

Pedro Magalhães

8 years ago
> > switch($a){ > case true: > //will match true, 1, etc... > break; > strict case false: > //will not match anything except boolean FALSE > //other stuff > break; > case false: > //will match 0, null, etc.... > break; > } >
I like this syntax, but I think I'd prefer the other way around. `case strict false:` describes better what the condition is. Regards, Pedro

Sebastian Bergmann

8 years ago
Am 14.06.2018 um 10:35 schrieb Nikita Popov:
> It might make sense to introduce an entirely new "match" statement > that conforms a bit more with how switch-like strictures are > implemented nowadays. That is, something like > > match ($expr) { > "foo" => {...}, > "bar" | "baz" => {...}, > } > > or similar.
Interesting. Can you provide a pointer to a language that has a match statement like that?

Christoph Becker

8 years ago
On 15.06.2018 at 08:36, Sebastian Bergmann wrote:
> Am 14.06.2018 um 10:35 schrieb Nikita Popov: > >> It might make sense to introduce an entirely new "match" statement >> that conforms a bit more with how switch-like strictures are >> implemented nowadays. That is, something like >> >> match ($expr) { >> "foo" => {...}, >> "bar" | "baz" => {...}, >> } >> >> or similar. > > Interesting. Can you provide a pointer to a language that has a match > statement like that?
This match statement (or would it be an expression?) could be regarded as an extremly simplified syntactic variant of the case-of expression of Standard ML[1]. Instead of the pipe operator we could use a comma to separate multiple “patterns”. Using “case” instead of “match” appears to be something to consider as well. [1] <https://www.cs.cornell.edu/courses/cs312/2004fa/lectures/lecture3.htm>, section “Pattern Matching”
-- Christoph M. Becker

Michał Brzuchalski

8 years ago
2018-06-15 11:44 GMT+02:00 Christoph M. Becker <cmbecker69@gmx.de>:
> On 15.06.2018 at 08:36, Sebastian Bergmann wrote: > > > Am 14.06.2018 um 10:35 schrieb Nikita Popov: > > > >> It might make sense to introduce an entirely new "match" statement > >> that conforms a bit more with how switch-like strictures are > >> implemented nowadays. That is, something like > >> > >> match ($expr) { > >> "foo" => {...}, > >> "bar" | "baz" => {...}, > >> } > >> > >> or similar. > > > > Interesting. Can you provide a pointer to a language that has a match > > statement like that? > > This match statement (or would it be an expression?) could be regarded > as an extremly simplified syntactic variant of the case-of expression of > Standard ML[1]. > > Instead of the pipe operator we could use a comma to separate multiple > “patterns”. Using “case” instead of “match” appears to be something to > consider as well. > > [1] > <https://www.cs.cornell.edu/courses/cs312/2004fa/lectures/lecture3.htm>, > section “Pattern Matching” > > -- > Christoph M. Becker > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: http://www.php.net/unsub.php > >
It's just a thought but maybe providing a new declare directive like `declare(strict_comparison=1);` be easier for those who prefer strict everywhere? We have `declare(strict_types=1);` so we may have stricter declares also. Maybe someday it turns into a standard way of working with PHP and can get rid of declares without any code changes. This may result in all comparisons strict without type juggling and won't need any syntax changes at all. And it'll apply for switch,if,else,ifselse,for,while etc. in all comparisons. Or maybe `declare(no_type_juggling=1)` or smth like that.
-- regards / pozdrawiam, -- Michał Brzuchalski about.me/brzuchal brzuchalski.com

Stas Malyshev

8 years ago
Hi!
> switch ($a) { > case FOO: > // Works exactly as current behavior. > break; > case == FOO: > // Nearly identical, though not using the ZEND_CASE optimization. > // Can probably make this equivalent to `case FOO`, but it felt > like an interesting direction. > break; > case === FOO: > // Only triggers if `$a === FOO`, no type juggling > break; > }
With current tendency to move to more strict interpretation and a bit away from type juggling, I think it has its place. But I am not a big fan to putting === there, it looks weird. Maybe go a bit further and make the whole switch strict? strict switch ($a) { case FOO: case BAR: // both are strict === } I imagine people that like strict style would want to use strict everywhere, so for them using === every time might be annoying. This way it makes for easier read for both strict and weak typers.
-- Stas Malyshev smalyshev@gmail.com

Jordi Boggiano

8 years ago
On 15/06/2018 00:10, Stanislav Malyshev wrote:
> With current tendency to move to more strict interpretation and a bit > away from type juggling, I think it has its place. But I am not a big > fan to putting === there, it looks weird. Maybe go a bit further and > make the whole switch strict? > > strict switch ($a) { > case FOO: > case BAR: > // both are strict === > }
Might I suggest a new strictwich ($a) { ... } keyword? It's much more appetizing. Apologies, Jordi
-- Jordi Boggiano @seldaek - https://seld.be

Rowan Collins

8 years ago
On 15 June 2018 at 14:48, Jordi Boggiano <j.boggiano@seld.be> wrote:
> Might I suggest a new strictwich ($a) { ... } keyword? It's much more > appetizing. >
Or maybe we should follow the pattern of == vs === and double up the "s": "sswitch ($a) { ... }" ;)
-- Rowan Collins [IMSoP]