# [VOTE] match expression

- Thread: https://externals.io/message/109842
- Original archive: https://news-web.php.net/php.internals/109842
- Started by Ilija Tovilo on 2020-04-25T10:39:46+00:00
- Messages: 23
- RFC: Match expression (Declined) — https://externals.io/rfc/match_expression.md
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · RFCs at https://externals.io/rfc.md · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #109842 — Ilija Tovilo — 2020-04-25T10:39:46+00:00

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

Hi internals

I have opened the voting on the match expression RFC. It will end on
9th of May, 2020.
https://wiki.php.net/rfc/match_expression

Here are the last changes:

In the last update I mentioned allowing return values in blocks.
Unfortunately, we discovered some technical difficulties (memory
leaks) which are very hard to solve. Nikita is experimenting on a
possible solution. There was also a fair bit of backlash over the
syntax. Thus I have decided to move block expressions to a separate
RFC. Note that blocks with just statements remain part of this RFC.

The "duplicate condition" warning mentioned by Dan was removed due to
the arguments made by Tyson.

I have also moved the optional semicolon for the match in statement
form to a separate vote as this was another controversial part of the
proposal.

Furthermore I have added another secondary vote for allowing to drop
(true) conditions as that was suggested multiple times:

match {
    $age >= 30 => {},
    $age >= 20 => {},
    $age >= 10 => {},
    default => {},
}

// Equivalent to

match (true) {
    $age >= 30 => {},
    $age >= 20 => {},
    $age >= 10 => {},
    default => {},
}

There is a separate poll for specifying the reason for a "no" vote.
Let me know if there are any other reasons so I can add those to the
poll.

A personal thank you goes out to Tyson for his guidance!

Regards,
Ilija

---

## #109843 — Dan Ackroyd — 2020-04-25T11:03:31+00:00

URL: https://externals.io/message/109842#109843 · In reply to: #109842

>
> Hi internals
>
> I have opened the voting on the match expression RFC. It will end on
> 9th of May, 2020.
> https://wiki.php.net/rfc/match_expression
>
> Here are the last changes:


Hi Ilija,

I like this idea, and would like to see 'match' in PHP. At the same
time, is there any need to have the vote right now? The deadline for
PHP 8 feature freeze is July 27 2020.

There were changes to the proposal overnight, which people have not
even had a chance to read, let alone think about. To me it feels like
the RFC is being rushed to a vote, with respect to the recent changes
and the technical problem you describe.

> Unfortunately, we discovered some technical difficulties (memory
> leaks) which are very hard to solve. Nikita is experimenting on a
> possible solution.

It also seems the voting options were also changed last night.

- The vote is a straight Yes/No vote for accepting the RFC and merging
the patch.

+ "Would you like to add match expressions to the language?"
+ "Should the semicolon for match in statement form be optional?"
+ "Should we allow dropping (true) condition?"

I think it would be better to continue the conversation and work
through the trade-offs when voting isn't active, rather than just
hoping people pick the correct choices, or have a contentious
time-limited discussion.

cheers
Dan
Ack

---

## #109844 — Bob Weinand — 2020-04-25T11:07:11+00:00

URL: https://externals.io/message/109842#109844 · In reply to: #109842

> Am 25.04.2020 um 12:39 schrieb Ilija Tovilo <tovilo.ilija@gmail.com>:
> 
> Hi internals
> 
> I have opened the voting on the match expression RFC. It will end on
> 9th of May, 2020.
> https://wiki.php.net/rfc/match_expression
> 
> Here are the last changes:
> 
> In the last update I mentioned allowing return values in blocks.
> Unfortunately, we discovered some technical difficulties (memory
> leaks) which are very hard to solve. Nikita is experimenting on a
> possible solution. There was also a fair bit of backlash over the
> syntax. Thus I have decided to move block expressions to a separate
> RFC. Note that blocks with just statements remain part of this RFC.
> 
> The "duplicate condition" warning mentioned by Dan was removed due to
> the arguments made by Tyson.
> 
> I have also moved the optional semicolon for the match in statement
> form to a separate vote as this was another controversial part of the
> proposal.
> 
> Furthermore I have added another secondary vote for allowing to drop
> (true) conditions as that was suggested multiple times:
> 
> match {
>    $age >= 30 => {},
>    $age >= 20 => {},
>    $age >= 10 => {},
>    default => {},
> }
> 
> // Equivalent to
> 
> match (true) {
>    $age >= 30 => {},
>    $age >= 20 => {},
>    $age >= 10 => {},
>    default => {},
> }
> 
> There is a separate poll for specifying the reason for a "no" vote.
> Let me know if there are any other reasons so I can add those to the
> poll.
> 
> A personal thank you goes out to Tyson for his guidance!
> 
> Regards,
> Ilija

Hey Ilija,

while in general I'm okay-ish with match using a strict comparison,

shall the "match { $cond1 => {}, $cond2 => {} }" syntax be strict or not? I would do a simple truthiness check in that particular case (which IMHO is also consistent as there is no explicit value it's compared against).
That way it would essentially have the semantics of a chained ternary without being illegible.

At least as match {} without explicit expected value is effectively a boolean comparison (doesn't feel really like a strict value comparison), it should also behave like a classical boolean comparison.

In general, apart from that very last change (I think you should have given it at least 1-2 days of consideration before starting the vote), the RFC is nice and provides a concise syntax for something which usually is quite uglily expressed.

Bob

---

## #109845 — Ilija Tovilo — 2020-04-25T11:23:06+00:00

URL: https://externals.io/message/109842#109845 · In reply to: #109843

Hi Dan

> I like this idea, and would like to see 'match' in PHP. At the same
> time, is there any need to have the vote right now? The deadline for
> PHP 8 feature freeze is July 27 2020.

I understand you sentiment. Let me put it this way: I've announced the
first version of this RFC four weeks ago and I still have absolutely
no idea what the general opinion is on this RFC, let alone the
details. So even if the RFC fails I'll gain some insight on how to
move forward.

Regards,
Ilija

---

## #109846 — tyson andre — 2020-04-25T15:35:10+00:00

URL: https://externals.io/message/109842#109846 · In reply to: #109842

Hi Ilija,

1. I was confused by the vote announcement email about what "block statements" meant - https://github.com/php/php-src/pull/5371#discussion_r415079802

> Thus I have decided to move block expressions to a separate RFC. 

This is clarified in https://wiki.php.net/rfc/match_expression#blocks 

> **For the time being using blocks in match expressions that use the return value in any way results in a compilation error:**

(I personally agree with that change for this RFC introducing `match`)

2. As Dan Ackroyd mentioned, https://wiki.php.net/rfc/howto mentions:

> When discussion ends, and a minimum period of two weeks has passed since you mailed internals@lists.php.net in step 4,
> consider one day heads up mail on the mailing list and then you can move your RFC to “Voting” status.

Other people may read the guidelines differently from me,
and I've made small mistakes with the process in the past due to not remembering everything in the howto.
(and they're guidelines instead of rules)
In the future, I'd recommend:

i. After finalizing the changes to the RFC and before starting the vote, email out a summary of what changed on the RFC discussion thread itself
   (https://externals.io/message/109590 "[DISCUSSION] Match expression")
ii. Consider waiting at least 24 hours before starting the vote, extending it if you made more changes to the RFC or implementation.
   This would give voters a clearer idea of what was being voted on, and give people time to point out issues/blockers/new questions with the new RFC/implementation (if needed).

P.S. Although it's obvious voting has started, and some other RFCs kept the title "Proposed Voting Choices",
https://wiki.php.net/rfc/match_expression#proposed_voting_choices could be renamed from "Proposed Voting Choices" to "Vote"

Thanks,
- Tyson

---

## #109850 — Marco Pivetta — 2020-04-26T08:15:11+00:00

URL: https://externals.io/message/109842#109850 · In reply to: #109842

Heya,

Just following up here, after private convo on why I voted "NO" on this RFC.

My rationale for not wanting the RFC (in its current state) is that I don't
want more procedural constructs in the language.

Specifically, I'm fine with:

match (<expression-to-be-matched>) {
    <potentially-matching-expression> =>
<result-expression-to-be-evaluated>,
    <potentially-matching-expression> =>
<result-expression-to-be-evaluated>,
    <potentially-matching-expression> =>
<result-expression-to-be-evaluated>,
    default => <result-expression-to-be-evaluated>,
}

I'm not fine with allowing procedural code to be executed on the
right-hand-side of each match.

It would still possible to hide procedural code in the right-hand-side of
the match, but luckily without affecting the outer scope:

match (<expression-to-be-matched>) {
    <potentially-matching-expression> => (function () { /* insert your
procedural nightmare of choice here */ })(),
    <potentially-matching-expression> => (fn () => /* more procedural
nightmares here */)(),
    default => <result-expression>,
}

By enforcing only expressions to be on the right-hand-side, we get some
nice side-effects too:

 * no need to discuss `continue`
 * no need to discuss `break`
 * no need to discuss `return`

Overall, that would be a win-win.

A point has been risen about the fact that using closures increases memory
usage and stack frames: that's a compiler optimization concern, and
probably also a minor one, since I'd discourage procedural code on the RHS
anyway :-)

I'd be voting YES on the RFC if the blocks were gone.

On Sat, Apr 25, 2020 at 12:40 PM Ilija Tovilo <tovilo.ilija@gmail.com>
wrote:

> Hi internals
>
> I have opened the voting on the match expression RFC. It will end on
> 9th of May, 2020.
> https://wiki.php.net/rfc/match_expression
>
> Here are the last changes:
>
> In the last update I mentioned allowing return values in blocks.
> Unfortunately, we discovered some technical difficulties (memory
> leaks) which are very hard to solve. Nikita is experimenting on a
> possible solution. There was also a fair bit of backlash over the
> syntax. Thus I have decided to move block expressions to a separate
> RFC. Note that blocks with just statements remain part of this RFC.
>
> The "duplicate condition" warning mentioned by Dan was removed due to
> the arguments made by Tyson.
>
> I have also moved the optional semicolon for the match in statement
> form to a separate vote as this was another controversial part of the
> proposal.
>
> Furthermore I have added another secondary vote for allowing to drop
> (true) conditions as that was suggested multiple times:
>
> match {
>     $age >= 30 => {},
>     $age >= 20 => {},
>     $age >= 10 => {},
>     default => {},
> }
>
> // Equivalent to
>
> match (true) {
>     $age >= 30 => {},
>     $age >= 20 => {},
>     $age >= 10 => {},
>     default => {},
> }
>
> There is a separate poll for specifying the reason for a "no" vote.
> Let me know if there are any other reasons so I can add those to the
> poll.
>
> A personal thank you goes out to Tyson for his guidance!
>
> Regards,
> Ilija
>

Marco Pivetta

http://twitter.com/Ocramius

http://ocramius.github.com/

---

## #109851 — Sebastian Bergmann — 2020-04-26T08:22:37+00:00

URL: https://externals.io/message/109842#109851 · In reply to: #109843

Am 25.04.2020 um 13:03 schrieb Dan Ackroyd:
> I like this idea, and would like to see 'match' in PHP. At the same
> time, is there any need to have the vote right now? The deadline for
> PHP 8 feature freeze is July 27 2020.
> 
> There were changes to the proposal overnight, which people have not
> even had a chance to read, let alone think about. To me it feels like
> the RFC is being rushed to a vote, with respect to the recent changes
> and the technical problem you describe.

I share this sentiment which is why I voted "no".

---

## #109852 — Sebastian Bergmann — 2020-04-26T08:25:05+00:00

URL: https://externals.io/message/109842#109852 · In reply to: #109850

Am 26.04.2020 um 10:15 schrieb Marco Pivetta:
> By enforcing only expressions to be on the right-hand-side, we get some
> nice side-effects too:
> 
>   * no need to discuss `continue`
>   * no need to discuss `break`
>   * no need to discuss `return`
> 
> Overall, that would be a win-win.

Makes sense to me.

> A point has been risen about the fact that using closures increases memory
> usage and stack frames: that's a compiler optimization concern, and
> probably also a minor one, since I'd discourage procedural code on the RHS
> anyway :-)

Agreed.

> I'd be voting YES on the RFC if the blocks were gone.

Same (I think).

---

## #109854 — Mark Randall — 2020-04-26T14:53:50+00:00

URL: https://externals.io/message/109842#109854 · In reply to: #109850

> I'm not fine with allowing procedural code to be executed on the
> right-hand-side of each match.
> 
> By enforcing only expressions to be on the right-hand-side, we get some
> nice side-effects too: > I'd be voting YES on the RFC if the blocks were gone.

I concur with Marco's statements.

Mark Randall
marandall@php.net

---

## #109859 — Andrea Faulds — 2020-04-27T13:56:40+00:00

URL: https://externals.io/message/109842#109859 · In reply to: #109843

Hi,

I share Dan's reasons for voting against. I don't think things should go 
to a vote before the dust has settled.

Regards,
Andrea Faulds

---

## #109868 — Nikita Popov — 2020-04-28T08:48:28+00:00

URL: https://externals.io/message/109842#109868

> Hi,
>
> I share Dan's reasons for voting against. I don't think things should go
> to a vote before the dust has settled.
>
> Regards,
> Andrea Faulds
>

Similar sentiment here. I don't think the concept has been explored
sufficiently.

Many people in the voting thread are calling for supporting match
expressions only (without support for either statement form, or support for
block expressions). The RFC motivates the match construct as an improved
replacement for switch, which is type-safe, exhaustive and has no
fallthrough gotchas. If we limit match to returning simple expressions
only, is it still a viable replacement for switch?

I've looked at a sample of ~50 switches randomly picked from popular
composer packages, the list can be found here:
https://gist.github.com/nikic/fc225f02ea76c02e669a598cfc471b83 I've
classified these according to whether the switches could be rewritten as a
match if it only supports expression, but not statement form. What I was
looking for here was the ability to more or less directly translate,
without having to do major refactoring first. Results:

2595: no (only with block expression support)
8337: no (only with block expression support)
2115: no
7109: no (only with block expression support)
6564: no
7786: no (only by returning a pair, and only realistic with block
expression support)
2609: yes
7450: no (only by returning a triple, and only with block expression
support)
5338: no
 567: no
3376: yes (but weird stylistically)
2850: no
2635: yes
  61: no
6562: no
2354: yes
 522: no
4972: yes
8179: no
6080: yes
5997: yes
6758: yes
6718: no (only with block expression support)
1451: maybe
9152: yes
4192: no
4099: no
6773: yes
2727: yes (but weird stylistically)
6779: yes
2710: no
 149: yes
7501: no
1197: no (only with block expression support)
6845: yes
6610: no
1088: yes (but weird stylistically)
2806: yes
3393: no
8361: no (only by returning a pair, and only with block expression support)
4473: no
8543: no
8792: no (only with block expression support, maybe)
8776: no
1165: yes
8388: yes
8294: no
3840: yes
3587: yes
6428: (empty switch)
8324: no
1280: no
2023: yes
8084: no (maybe with block expression support)

Of the switches I looked at, 31 cannot use match in single-expression form,
while 21 can.

Is match intended as a replacement for switch? Or is intended to replace
the ternary operator? Do we want people to be able to convert switches to
matches without much hassle, or is this only intended for a specific
subset? I'm not quite clear on what "match" is intended to be, and I think
different people in this discussion have rather different views on this.

Regards,
Nikita

---

## #109869 — Rowan Tommins — 2020-04-28T09:23:50+00:00

URL: https://externals.io/message/109842#109869 · In reply to: #109868

> Many people in the voting thread are calling for supporting match
> expressions only (without support for either statement form, or support
for
> block expressions). The RFC motivates the match construct as an improved
> replacement for switch, which is type-safe, exhaustive and has no
> fallthrough gotchas. If we limit match to returning simple expressions
> only, is it still a viable replacement for switch?
[...]
> Is match intended as a replacement for switch? Or is intended to replace
> the ternary operator?


Two thoughts on this:

1) Why does it need to *replace* anything? Introducing switch to a language
isn't usually considered a replacement for if-elseif-else, even though the
usage overlaps heavily. Instead, it's seen as an extra tool in the chest,
with its own strengths and weaknesses. I think it's better to focus on what
the use cases are, rather than how they'd currently be written. In other
words, the fact that it's not a straight replacement for switch may be a
feature, not a bug.

2) As a thought experiment, imagine splitting the current proposal into
two: a new conditional expression, and a new control-flow statement. To me,
the syntax currently proposed works really nicely for the conditional
expression; for the control-flow statement, it feels awkward and not in
keeping with the rest of the language. If they were separate proposals, the
statement would probably end up looking very different. That's why it feels
more natural to suggest dropping the statement and keeping the expression
than the other way around.

Regards,
-- 
Rowan Tommins
[IMSoP]

---

## #109870 — Ilija Tovilo — 2020-04-28T10:18:42+00:00

URL: https://externals.io/message/109842#109870 · In reply to: #109868

Hi Nikita

Thank you for your analysis. That's something I should've done as part
of the RFC.

I can only share my personal motivation for creating this RFC. Some
people will disagree.

> Is match intended as a replacement for switch?

To me, match is primarily a switch alternative with safer semantics.
While it is very nice that match evaluates to the executed arm I think
statement matches would be more common and more useful. Your analysis
seems to align with that.

> If we limit match to returning simple expressions
> only, is it still a viable replacement for switch?

I don't think so. Of course, some people might argue that the switch
is fine and doesn't need a replacement which is an entirely valid
viewpoint. However, that would directly contradict most of the
arguments made in the RFC. If the switch is fine adding another
alternative with different semantics is questionable. If the issues
listed in the RFC are valid IMO this RFC only makes sense supporting
blocks.

> Of the switches I looked at, 31 cannot use match in single-expression form,
> while 21 can.

I think that sums it up nicely. Let's also remember that these are
popular, well maintained repositories and probably don't reflect the
average code quality very well.

Let me also address Rowans comment:

> Why does it need to *replace* anything? Introducing switch to a language
> isn't usually considered a replacement for if-elseif-else, even though the
> usage overlaps heavily.

The if statement doesn't have (most of) the issues stated in the RFC.
Match is a direct response to the flaws of the switch. Without blocks
match won't actually be usable in most of these cases and you'll be
stuck with switch and its flaws. Again, you can argue the switch
doesn't have flaws but then the whole RFC doesn't make any sense.

> for the control-flow statement, it feels awkward and not in
> keeping with the rest of the language. If they were separate proposals, the
> statement would probably end up looking very different.

Can you elaborate? If I made a proposal exclusively for match
statements the syntax would be exactly equivalent.

Ilija

---

## #109871 — Rowan Tommins — 2020-04-28T10:48:51+00:00

URL: https://externals.io/message/109842#109871 · In reply to: #109870

> > […]
> the
> > […]
>
> Can you elaborate? If I made a proposal exclusively for match
> statements the syntax would be exactly equivalent.
>


If we take away the expression part, the proposal would be to replace this
switch statement:

switch ( $expr ) {
     case 1:
     case 2:
           statement;
     break;
     default:
           statement;
     break;
}

With this match statement:

match ( $expr ) {
     1, 2 => {
           statement;
     },
     default => {
           statement;
     },
}

The extra set of {} inside looks a little odd, but is a reasonable way to
remove the implicit fallthrough. However, the other changes seem to just be
arbitrarily new syntax:

* No "case" keyword
* => instead of :
* commas between statement blocks

If the motivation is simply to fix the current switch statement, why not
keep the syntax more familiar?

match ( $expr ) {
     case 1, 2: {
           statement;
     }
     default: {
           statement;
     }
}

The colon looks unnecessary next to the opening brace, but if we keep it,
the braces could be optional like they are in an if statement:

match ( $expr ) {
     case 1, 2: statement;
     default: statement;
}

Note that this wouldn't suffer the problems of accidentally running code
that you get with one-line if statements, because the following could
simply be a syntax error:

match ( $expr ) {
     case 1, 2: statement; anotherStatement;
     default: statement;
}


That syntax doesn't lend itself as well to being used as an expression, but
I'm not convinced making one syntax work for both use cases is the right
goal given the compromises it requires.


Regards,
-- 
Rowan Tommins
[IMSoP]

---

## #109877 — Bob Weinand — 2020-04-28T15:10:31+00:00

URL: https://externals.io/message/109842#109877 · In reply to: #109871

> Am 28.04.2020 um 12:48 schrieb Rowan Tommins <rowan.collins@gmail.com>:
> 
> 
> 
> > […]
> 
> 
> If we take away the expression part, the proposal would be to replace this
> switch statement:
> 
> switch ( $expr ) {
>     case 1:
>     case 2:
>           statement;
>     break;
>     default:
>           statement;
>     break;
> }
> 
> With this match statement:
> 
> match ( $expr ) {
>     1, 2 => {
>           statement;
>     },
>     default => {
>           statement;
>     },
> }
> 
> The extra set of {} inside looks a little odd, but is a reasonable way to
> remove the implicit fallthrough. However, the other changes seem to just be
> arbitrarily new syntax:
> 
> * No "case" keyword
> * => instead of :
> * commas between statement blocks
> 
> If the motivation is simply to fix the current switch statement, why not
> keep the syntax more familiar?
> 
> match ( $expr ) {
>     case 1, 2: {
>           statement;
>     }
>     default: {
>           statement;
>     }
> }
> 
> The colon looks unnecessary next to the opening brace, but if we keep it,
> the braces could be optional like they are in an if statement:
> 
> match ( $expr ) {
>     case 1, 2: statement;
>     default: statement;
> }
> 
> Note that this wouldn't suffer the problems of accidentally running code
> that you get with one-line if statements, because the following could
> simply be a syntax error:
> 
> match ( $expr ) {
>     case 1, 2: statement; anotherStatement;
>     default: statement;
> }
> 
> 
> That syntax doesn't lend itself as well to being used as an expression, but
> I'm not convinced making one syntax work for both use cases is the right
> goal given the compromises it requires.
> 
> 
> Regards,
> -- 
> Rowan Tommins
> [IMSoP]

Hey Rowan,

I think you should first think about why the "case" needs to exists at all. In particular it exists to distinguish goto labels from the case expressions in switch. With match, match restricting statements (and thus goto labels) into { brackets }, it now is not necessary to do such a distinction and we can get rid of the extra token.
"=>" is logical as well, we use the return value of the expressions (see fn() and array syntax), the colon is exclusively used for pure statement boundaries.
The comma is necessary for the expression syntax at least (consider match($a) { 1 => 2  + 2 + 2 => 3 } - is this now match($a) { 1 => 2, (2 + 2) => 3 } or match ($a) { 1 => (2 + 2), +2 => 3 } ?) You may argue to make it optional behind a statement block though.

Bob

---

## #109879 — Rowan Tommins — 2020-04-28T15:31:16+00:00

URL: https://externals.io/message/109842#109879 · In reply to: #109877

> I think you should first think about why the "case" needs to exists at
> all. In particular it exists to distinguish goto labels from the case
> expressions in switch. With match, match restricting statements (and thus
> goto labels) into { brackets }, it now is not necessary to do such a
> distinction and we can get rid of the extra token.
>


That may be obvious if you're used to writing parsers, but to users, the
case keyword is simply how switch statements work. Removing it just makes
the new statement look less familiar and isn't justified by the aims stated
in the RFC.



> "=>" is logical as well, we use the return value of the expressions (see
> fn() and array syntax), the colon is exclusively used for pure statement
> boundaries.
>


You've missed the context of my e-mail: I was explicitly discussing a
hypothetical syntax that *doesn't* resolve to a value, and where the colon
*is* introducing a statement not an expression.



> The comma is necessary for the expression syntax at least (consider
> match($a) { 1 => 2  + 2 + 2 => 3 } - is this now match($a) { 1 => 2, (2 +
> 2) => 3 } or match ($a) { 1 => (2 + 2), +2 => 3 } ?) You may argue to make
> it optional behind a statement block though.



Again, expressions are explicitly out of scope for this thought experiment.
As such, the result of every case is delimited either by a closing brace or
a semi-colon, and the above example is simply a syntax error.


As I've said many times now, I really like the match expression, with the
current syntax, as a pure expression. I was explicitly addressing the
question of why I think a straight-forward switch replacement would not
look the same if we weren't trying to squeeze two features into one syntax.

Regards,
-- 
Rowan Tommins
[IMSoP]

---

## #109897 — Larry Garfield — 2020-04-29T00:26:59+00:00

URL: https://externals.io/message/109842#109897 · In reply to: #109879

> 
> 
> > […]
> 
> 
> That may be obvious if you're used to writing parsers, but to users, the
> case keyword is simply how switch statements work. Removing it just makes
> the new statement look less familiar and isn't justified by the aims stated
> in the RFC.
> 
> 
> 
> > […]
> 
> 
> You've missed the context of my e-mail: I was explicitly discussing a
> hypothetical syntax that *doesn't* resolve to a value, and where the colon
> *is* introducing a statement not an expression.
> 
> 
> 
> > […]
> 
> 
> 
> Again, expressions are explicitly out of scope for this thought experiment.
> As such, the result of every case is delimited either by a closing brace or
> a semi-colon, and the above example is simply a syntax error.
> 
> 
> As I've said many times now, I really like the match expression, with the
> current syntax, as a pure expression. I was explicitly addressing the
> question of why I think a straight-forward switch replacement would not
> look the same if we weren't trying to squeeze two features into one syntax.
> 
> Regards,
> -- 
> Rowan Tommins
> [IMSoP]


I agree that there seems to be two entirely different problem spaces being smushed together here, which is creating a problem (both for the code and for the discussion).  Which... suggests we really should try to split them up.

To that end, I'm going to refer to them as rustmatch (an expression that only supports expressions and returns things; basically a fancier alternative to ternary) and switchtng (a procedural branching statement that is basically switch but with the lessons of the 40 years since C switch was invented, which PHP blindly inherited) to avoid privileging one or the other.

Based on the current RFC voting, it seems like there's strong interest in rustmatch, using the syntax currently proposed:

$expressionResult = match ($condition) {
    1, 2 => foo(),
    3, 4 => bar(),
    default => baz(),
};

I'm calling this "rustmatch" because its semantics and syntax are largely borrowed from Rust's match expression (https://aminb.gitbooks.io/rust-for-c/content/control_flow/index.html).  (Yes, Rust supports multi-line expressions but it does all over the place, which is a separate issue.)

The other is what, I think, Ilja was originally trying to do, which is a more Go-style switch (https://gobyexample.com/switch) than a C-style switch.  That is, still a procedural construct but less bug-prone.

One issue that was discussed a few weeks ago, and led to the current syntax, was too many variations within the switch syntax; of course, trying to do it all in one syntax is perpetuating that problem.  However, I think Rowan has suggested a syntax that may be sufficiently self-documenting.  To wit, independent of rustmatch (above):

switch ($foo) {
  case 1: {
    Many statements here.
  }
  case 2: {
    Many statements here.
  }
}

The curly braces are already understood by most PHPers to mean "a block of statements", and so it's a logical jump in this case.  As Rowan suggests, the {} imply a break.  To keep it simple we should probably not allow mixing and matching in a single switch.  Either list-style (break required) or {}-style (break implied).

That handles break; the other problems listed in the RFC for switch are:

* weak comparison
* Inexhaustive
* No return

The no-return is only an issue for the expression-centric approach, which belongs to rustmatch, and thus in a split approach is off topic.  If you want multi-prong branching that evaluates to a returned value... use the rustmatch option and be done with it, go away.

For the other two, would a simple "strict" keyword be acceptable to people?  The net result being:

switch strict ($foo) {
  case 1: {
    Many statements here.
  }
  case 2: {
    Many statements here.
  }
}

That does a strict type comparison on $foo, triggers a warning/error/whatever if nothing matches (default is still supported of course), and the curly braces replace break.  It can NOT return anything, but that's OK, because it's a flow control construct, not an expression.  Never the twain shall meet.

If this seems reasonable to folks, particularly Ilja, I'd suggest pulling the current vote/letting it expire, and then reintroducing it as *just* an expression, with single-expressions only, semi-colon required always, and an implicit default match value of true (as the current polls very strongly indicate; thank you Ilja for including the extra data gathering).  Then in parallel introduce a second RFC that adds the strict keyword and {} alternative, and *nothing else*.  Let that have its own, separate vote.

Based on the current voting I strongly suspect the more limited match expression v2 would pass easily.  I don't know if the strict switch would pass or not, but it would at least be able to get a fair shake on its own without trying to do double-duty as an expression and a statement at the same time, which the current RFC is trying to do.

--Larry Garfield

---

## #109899 — Levi Morrison via internals — 2020-04-29T00:37:36+00:00

URL: https://externals.io/message/109842#109899 · In reply to: #109897

> One issue that was discussed a few weeks ago, and led to the current syntax, was too many variations within the switch syntax; of course, trying to do it all in one syntax is perpetuating that problem.  However, I think Rowan has suggested a syntax that may be sufficiently self-documenting.  To wit, independent of rustmatch (above):
>
> switch ($foo) {
>   case 1: {
>     Many statements here.
>   }
>   case 2: {
>     Many statements here.
>   }
> }
>
> The curly braces are already understood by most PHPers to mean "a block of statements", and so it's a logical jump in this case.  As Rowan suggests, the {} imply a break.  To keep it simple we should probably not allow mixing and matching in a single switch.  Either list-style (break required) or {}-style (break implied).
>
> That handles break;

Sadly, it doesn't. That code is valid today:

    <?php
    $foo = 1;
    switch ($foo) {
        case 1: {
            echo "1\n";
        }
        case 2: {
            echo "2\n";
        }
    }
    ?>

Which outputs:
1
2

---

## #109900 — Larry Garfield — 2020-04-29T00:57:30+00:00

URL: https://externals.io/message/109842#109900 · In reply to: #109899

> > […]
> 
> Sadly, it doesn't. That code is valid today:
> 
>     <?php
>     $foo = 1;
>     switch ($foo) {
>         case 1: {
>             echo "1\n";
>         }
>         case 2: {
>             echo "2\n";
>         }
>     }
>     ?>
> 
> Which outputs:
> 1
> 2

... Well, crap.  It just can't be easy, can it...

Would it be too context-sensitive to have the {} version only work in strict switch?

Or for that matter... is anyone actually using that syntax in the wild, or is it hypothetical?  Viz, if the behavior of that changed in 8.0 (a major release), would that even break anything?  Even 7.4 has a couple of "the behavior changed but seriously who was using this anyway?" points in it.  Could we get away with just changing it for 8.0?

I'm not sure if Nikita's "check the top 1000" script could handle something that subtle.

--Larry Garfield

---

## #109901 — Levi Morrison via internals — 2020-04-29T01:19:58+00:00

URL: https://externals.io/message/109842#109901 · In reply to: #109900

>
> 
> > […]
>
> ... Well, crap.  It just can't be easy, can it...
>
> Would it be too context-sensitive to have the {} version only work in strict switch?
>
> Or for that matter... is anyone actually using that syntax in the wild, or is it hypothetical?  Viz, if the behavior of that changed in 8.0 (a major release), would that even break anything?  Even 7.4 has a couple of "the behavior changed but seriously who was using this anyway?" points in it.  Could we get away with just changing it for 8.0?
>
> I'm not sure if Nikita's "check the top 1000" script could handle something that subtle.
>
> --Larry Garfield
>
> --
> 
> 


I am confident it was used in a former employer's codebase, which is
how I immediately knew it was valid. My memory is too fuzzy to
remember anything more than it was used, unfortunately.

---

## #109903 — Ilija Tovilo — 2020-04-29T06:41:07+00:00

URL: https://externals.io/message/109842#109903 · In reply to: #109900

> Or for that matter... is anyone actually using that syntax in the wild, or is it hypothetical?

It's quite common in C (you can't declare variables directly in a
switch case) so I'd guess it would be used at least by some people in
PHP.

The worst part is that your code wouldn't throw, it would just start
behaving differently.

Looking at grep.app you'll find quite a few of them.
https://grep.app/search?q=%3A%20%7B&filter[lang][0]=PHP
(Note that searching with regex won't work as that only shows a very
small subset of results.)

Ilija

---

## #109922 — Larry Garfield — 2020-04-29T13:33:16+00:00

URL: https://externals.io/message/109842#109922 · In reply to: #109903

> > […]
> 
> It's quite common in C (you can't declare variables directly in a
> switch case) so I'd guess it would be used at least by some people in
> PHP.
> 
> The worst part is that your code wouldn't throw, it would just start
> behaving differently.
> 
> Looking at grep.app you'll find quite a few of them.
> https://grep.app/search?q=%3A%20%7B&filter[lang][0]=PHP
> (Note that searching with regex won't work as that only shows a very
> small subset of results.)
> 
> Ilija

Well, poopy.

I still think splitting the RFC in half (rust-style match and Go-style switch) is the correct way forward, whatever the syntax particulars.

--Larry Garfield

---

## #109932 — Rowan Tommins — 2020-04-29T17:22:17+00:00

URL: https://externals.io/message/109842#109932 · In reply to: #109897

> To that end, I'm going to refer to them as rustmatch (an expression that only supports expressions and returns things; basically a fancier alternative to ternary) and switchtng (a procedural branching statement that is basically switch but with the lessons of the 40 years since C switch was invented, which PHP blindly inherited) to avoid privileging one or the other.


I like the codenames. :)

Thinking about it, I think the "switchng" syntax can be even more 
conservative. The RFC lists four issues with switch, of which three 
would be applicable to a "switchng" RFC:

1. Type coercion
2. Fallthrough
3. Inexhaustiveness

For #1, the only thing we need is some way to opt into "strict mode" on 
the switch statement, and have the comparisons handled by === rather 
than ==. That could be as simple as writing "switch strict" instead of 
"switch".

For #2, the problem is that fallthrough is implicit where no "break" is 
present, so what if we just said that reaching another "case" statement 
was a runtime error in a switchng statement? That would mean any 
existing switch statement that didn't use fallthrough could be 
"upgraded" without changing its body at all.

We could allow multiple case labels with no statements between, allowing 
for the common scenario of multiple conditions running identical code. 
Alternatively (or as a separate enhancement) we could allow 
comma-separated lists in case blocks (on both normal switch and switchng).

For other cases of fallthrough, we could add a new keyword (or recycle 
"continue") to explicitly go to the next case. That could even be left 
to "Future Scope", because anyone wanting it can always "downgrade" to 
the version with implicit fallthrough.

Finally, #3 can be part of the same "strict mode", with one of two 
behaviours:

a) Make a switchng with no "default:" clause a compile-time error
b) Make a switchng which doesn't match any case a run-time error, 
effectively adding an implicit clause of "default: throw new Error(); 
break;"


So our shiny new "switchng" statement would look ... exactly the same as 
a normal switch statement, but with one new keyword, and the ability to 
throw two new errors.


Regards,

-- 
Rowan Tommins (né Collins)
[IMSoP]
