Re: [RFC] switch expression
| From: | Michał Brzuchalski | Date: | Wed, 25 Mar 2020 14:17:26 +0000 |
| Subject: | Re: [RFC] switch expression | ||
| References: | 1 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-109291@lists.php.net to get a copy of this message | ||
Hi Ilija,
śr., 25 mar 2020 o 13:10 Ilija Tovilo <ilija.tovilo@me.com> napisał(a):
> Hi everybody!
>
>
>
> A few years ago I suggested adding a new
match expression to
> the PHP
> language:
>
> https://externals.io/message/100487
>
>
>
> I arrogantly assumed someone will implement it for me which of course
> didn't happen. I'd finally like to get my own hands dirty. I have a very
> rough, incomplete prototype but I'd like to get your feedback before I
> continue working on the details.
>
>
>
> # Introduction
>
>
>
> This is what it looks like:
>
>
>
> ```php
>
> echo $i switch {
>
> 0 => "i equals 0",
>
> 1 => "i equals 1",
>
> 2 => "i equals 2",
>
> 3, 4 => "i equals 3 or 4",
>
> };
>
>
>
> // is roughly equivalent to
>
>
>
> switch ($i) {
>
> case 0:
>
> $tmp = "i equals 0";
>
> break;
>
> case 1:
>
> $tmp = "i equals 1";
>
> break;
>
> case 2:
>
> $tmp = "i equals 2";
>
> break;
>
> case 3:
>
> case 4:
>
> $tmp = "i equals 3 or 4";
>
> break;
>
> default:
>
> throw new InvalidArgumentException('Unhandled switch case');
>
> }
>
>
>
> echo $tmp;
>
> ```
>
>
>
> Some things to note:
>
>
>
> * Each case only accepts a single expression
>
> * The entire switch expression evaluates to the result of the executed case
>
> * There is no fallthrough, an implicit break is added after every case
>
> * Multiple case conditions are possible with comma separation
>
> * The default case throws a InvalidArgumentException by default
>
> * The switch keyword is used as an infix operator
>
>
>
> # Syntax
>
>
>
> Originally, I expected to reuse the current syntax and transform it into
> an expression.
>
>
>
> ```php
>
> $x = switch ($y) { ... };
>
> ```
>
>
>
> Turns out this is ambiguous.
>
>
>
> ```php
>
> switch ($y) { ... }
>
> [$a] = ...;
>
>
>
> // Could also be interpreted as
>
> switch ($y) { ... }[$a] = ...;
>
> ```
>
>
>
> I stole the new syntax from C# 8.0 which means at least some people will
> already be familiar with it:
>
>
>
> https://docs.microsoft.com/en-us/archive/msdn-magazine/2019/may/csharp-8-0-pattern-matching-in-csharp-8-0#the-evolution-of-pattern-matching-in-c-80
>
>
>
> # Type coercion
>
>
>
> One of the bigger weak points of the switch statement is the
> fact that
> it performs implicit type coercion.
>
>
>
> ```php
>
> switch ('foo') {
>
> case 0:
>
> echo "Oh no!\n";
>
> }
>
> ```
>
>
>
> While it's very tempting to fix this in the new switch
> expression it
> adds a confusing discrepancy between the switch statement and
> expression.
> I think it would be preferrable to keep the two the same and change the
> behavior of both in a new PHP edition (
> https://github.com/php/php-rfcs/pull/2).
>
>
>
> # Pattern matching
>
>
>
> I decided against pattern matching because PHP doesn't have algebraic data
> types and classes rarely have public properties. In my opinion the limited
> use cases don't justify the significant complexity added to the language.
> It would also, once again, add an unjustified discrepancy between the
> switch statement and expression. If at some point we do want to
> introduce
> pattern matching it might be better to introduce a different keyword (e.g..
> match) and make it work for both the statement and expression.
> In case
> you need to match a more complex expression the following still works fine:
>
>
>
> ```php
>
> echo true switch {
>
> is_int($x) => 'int',
>
> is_float($x) => 'float',
>
> is_string($x) => 'string',
>
> ...
>
> };
>
> ```
>
>
>
> # Blocks
>
>
>
> Sometimes it would be useful to split the expression into multiple
> statements to make it more readable. Unfortunately, in PHP there are no
> block expressions. Rust allows returning the last value by omitting the
> semicolon:
>
>
>
> ```php
>
> echo $x switch {
>
> 1 => {
>
> foo();
>
> bar();
>
> baz()
>
> },
>
> };
>
> ```
>
>
>
> This is indeed possible in PHP and could be implemented as part of the
> switch expression or as a general language feature. A nice side
> effect is
> that this could also be used in arrow functions:
>
>
>
> ```php
>
> $x = fn() => {
>
> foo();
>
> bar();
>
> baz()
>
> };
>
> ```
>
>
>
> This would, however, make it inconsistent with closures as they use the
> return keyword. Thus we would probably have to make sure arrow functions
> still work with return statement which would decrease the need for such a
> language construct. It is also very unlike anything else in PHP.
>
>
>
> # Poll
>
>
>
> This is a short overview of what I'll be working on in the coming weeks. I
> created a short poll for you guys to let me know if this idea is worth
> pursuing:
>
> https://forms.gle/stXMv72CAaDDxfwf8
>
>
>
> Stay safe!
>
>
That looks like what I've described a few months ago in
https://wiki.php.net/rfc/switch-expression-and-statement-improvement
If you dig into the mailing list you can even find almost ready to use
patch which implements it.
I'd love switch expression inclusion in PHP.
Cheers,
Michał Brzuchalski