Re: [PHP-DEV] [RFC] switch expression

This is only part of a thread. view whole thread
  109295
March 25, 2020 15:29 ilija.tovilo@me.com (Ilija Tovilo)
Thanks for your feedback, Larry!

> One possible improvement to either version is allowing an expression on the left side. That is, rather than doing an equality match, do a boolean match.
This is how Rust does it: ```rust let x = match ... { Some(y) if y < 5 => ... } ``` In other words, you can add an additional guard to each case that excepts any expression. We don't really benefit a lot from that since we don't have pattern matching. I don't think this would add any significant benefit over: ```php $x = true switch { $x !== null && $x < 5 => ... } ``` Regards
  109296
March 25, 2020 15:46 larry@garfieldtech.com ("Larry Garfield")
On Wed, Mar 25, 2020, at 10:29 AM, Ilija Tovilo wrote:
> Thanks for your feedback, Larry! > > > One possible improvement to either version is allowing an expression on the left side. That is, rather than doing an equality match, do a boolean match. > > This is how Rust does it: > > ```rust > let x = match ... { > Some(y) if y < 5 => ... > } > ``` > > In other words, you can add an additional guard to each case that > excepts any expression. We don't really benefit a lot from that since > we don't have pattern matching. I don't think this would add any > significant benefit over: > > ```php > $x = true switch { > $x !== null && $x < 5 => ... > } > ```
Good point, I'd forgotten about that potential trick. So as long as an expression is allowed on the left, rather than just a literal, which is then == compared against the provided value, that should be "good enough" for most use cases. The implementation should include some tests to make sure that works properly, but I'm happy with the resulting syntax. So then the net result is: $var = switch($val) { case expr1 => expr2; } Where $val gets compared against the result of each expr1, and if true then $var is set to expr2. Endorse. --Larry Garfield
  109297
March 25, 2020 16:06 php@dennis.birkholz.biz (Dennis Birkholz)
Hello together,

Am 25.03.20 um 16:46 schrieb Larry Garfield:
> On Wed, Mar 25, 2020, at 10:29 AM, Ilija Tovilo wrote: >> Thanks for your feedback, Larry! >> >>> One possible improvement to either version is allowing an expression on the left side. That is, rather than doing an equality match, do a boolean match. >> >> This is how Rust does it: >> >> ```rust >> let x = match ... { >> Some(y) if y < 5 => ... >> } >> ``` >> >> In other words, you can add an additional guard to each case that >> excepts any expression. We don't really benefit a lot from that since >> we don't have pattern matching. I don't think this would add any >> significant benefit over: >> >> ```php >> $x = true switch { >> $x !== null && $x < 5 => ... >> } >> ``` > > Good point, I'd forgotten about that potential trick. So as long as an expression is allowed on the left, rather than just a literal, which is then == compared against the provided value, that should be "good enough" for most use cases. > > The implementation should include some tests to make sure that works properly, but I'm happy with the resulting syntax. > > So then the net result is: > > $var = switch($val) { > case expr1 => expr2; > } > > Where $val gets compared against the result of each expr1, and if true then $var is set to expr2.
on the first glance this all looks nice but you actually created something more like an if-expression that uses switch as a keyword because you stripped switch of some of its major features: - you compare the given value to possible cases -> you compare expressions to true - you can fall through to other cases without break - what about the default case? What about the following if-expression-syntax: $var = if ($x > 0) { return 1; } elseif ($x < 0) { return -1; } else { return 0; } Maybe this is more in line of what you want to do with your switch expression? Greets Dennis
  109300
March 25, 2020 16:22 ilija.tovilo@me.com (Ilija Tovilo)
Hi Dennis

Thanks for your feedback!

> you can fall through to other cases without break
You could do the same using the || operator.
> what about the default case?
I haven't described the default case in my proposal but it is exactly what you'd expect it to be: ```php $var = true switch { $x > 0 => 1, $x < 0 => -1, default => 0, }; ```
> What about the following if-expression-syntax:
That would work (once again, Rust already does it) though not with the return keyword. We'd still need a block expression to pass the value from the block to the if expression. When I compare the two I definitely think the match expression is more readable. Regards
  109303
March 25, 2020 16:51 cmbecker69@gmx.de ("Christoph M. Becker")
On 25.03.2020 at 17:06, Dennis Birkholz wrote:
> Hello together, > > Am 25.03.20 um 16:46 schrieb Larry Garfield: >> On Wed, Mar 25, 2020, at 10:29 AM, Ilija Tovilo wrote: >>> Thanks for your feedback, Larry! >>> >>>> One possible improvement to either version is allowing an expression on the left side. That is, rather than doing an equality match, do a boolean match. >>> >>> This is how Rust does it: >>> >>> ```rust >>> let x = match ... { >>> Some(y) if y < 5 => ... >>> } >>> ``` >>> >>> In other words, you can add an additional guard to each case that >>> excepts any expression. We don't really benefit a lot from that since >>> we don't have pattern matching. I don't think this would add any >>> significant benefit over: >>> >>> ```php >>> $x = true switch { >>> $x !== null && $x < 5 => ... >>> } >>> ``` >> >> Good point, I'd forgotten about that potential trick. So as long as an expression is allowed on the left, rather than just a literal, which is then == compared against the provided value, that should be "good enough" for most use cases. >> >> The implementation should include some tests to make sure that works properly, but I'm happy with the resulting syntax. >> >> So then the net result is: >> >> $var = switch($val) { >> case expr1 => expr2; >> } >> >> Where $val gets compared against the result of each expr1, and if true then $var is set to expr2. > > on the first glance this all looks nice but you actually created > something more like an if-expression that uses switch as a keyword > because you stripped switch of some of its major features: > - you compare the given value to possible cases -> you compare > expressions to true > - you can fall through to other cases without break > - what about the default case? > > What about the following if-expression-syntax: > > $var = if ($x > 0) { return 1; } > elseif ($x < 0) { return -1; } > else { return 0; } > > Maybe this is more in line of what you want to do with your switch > expression?
Or maybe even $var = $x > 0 ? 1 :($x < 0 ? -1 : 0); Yes, the required parentheses are ugly, but in my opinion, this is still better than a new if or switch(true) expression construct. -- Christoph M. Becker
  109299
March 25, 2020 16:21 rowan.collins@gmail.com (Rowan Tommins)
On Wed, 25 Mar 2020 at 15:29, Ilija Tovilo tovilo@me.com> wrote:

> I don't think this would add any significant benefit over: > > ```php > $x = true switch { > $x !== null && $x < 5 => ... > } > ``` >
The problem with that is that it requires a temporary variable to be switched on. If I want to switch on, say, a method call, I can write this for equality: $result = $this->foo($bar) switch { 1 => 'hello', 2 => 'hi', 3 => 'goodbye' }; For inequalities, the switch(true) version looks something like this (the parentheses would probably be optional, but I'd personally use them for readability): $temp = $this->foo($bar); $result = true switch { ($temp <= 1) => 'hello', ($temp == 2) => 'hi', default => 'goodbye' } Using $$ to mean "value tested" would mean you could get rid of the temp variable, and just write this: $result = $this->foo($bar) switch { ($$ <= 1) => 'hello', ($$ == 2) => 'hi', default => 'goodbye' }; I've also previously thought about specifying an operator for switch statements, which could be used with expressions as well, e.g. $result = $this->foo($bar) switch <= { 1 => 'hello', 2 => 'hi', default => 'goodbye' }; Again, though, this is something that could be added to switch statements and expressions together, as a separate RFC. Regards, -- Rowan Tommins [IMSoP]
  109301
March 25, 2020 16:28 ilija.tovilo@me.com (Ilija Tovilo)
Hi Rowan

> The problem with that is that it requires a temporary variable to be > switched on. If I want to switch on, say, a method call, I can write this > for equality:
I agree. The iffy part would be recognizing if the case expression should be equated to the switch input or evaluated on its own. That is still something we could address in a later RFC for both the statement and expression. Regards
  109306
March 25, 2020 18:24 php@manuelcanga.dev (Manuel Canga)
Hi, internals,


 ---- En mié, 25 mar 2020 17:21:29 +0100 Rowan Tommins collins@gmail.com> escribió ----
 > On Wed, 25 Mar 2020 at 15:29, Ilija Tovilo tovilo@me.com> wrote:
 > 
 > > I don't think this would add any significant benefit over:
 > >
 > > ```php
 > > $x = true switch {
 > >     $x  !== null && $x < 5 => ...
 > > }
 > > ```
 > >
 > 
 > 
 > The problem with that is that it requires a temporary variable to be
 > switched on. If I want to switch on, say, a method call, I can write this
 > for equality:
 > 
 > $result = $this->foo($bar) switch {
 >     1 => 'hello',
 >     2 => 'hi',
 >     3 => 'goodbye'
 > };

In this case, you can also do:

$result =  [
    1 => 'hello',
    2 => 'hi',
    3 => 'goodbye'
 ][$this->foo($bar)];

With syntax very similar to proposed switch but this is using array.

Regards
 --
Manuel Canga