Re: 'switch-expression' and the 'type guard' unary operator demo
| From: | Rowan Tommins | Date: | Sun, 20 Oct 2019 11:59:32 +0000 |
| Subject: | Re: 'switch-expression' and the 'type guard' unary operator demo | ||
| References: | 1 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-107588@lists.php.net to get a copy of this message | ||
Hi Kosit,
There's some really interesting ideas in here, thanks for sharing them.
On 19/10/2019 17:40, Kosit Supanyo wrote:
Like function declaration and function expression in JavaScript, ifThis feels like an odd restriction to me, and one that as far as I'm aware PHP doesn't have anywhere else. For instance, it might be considered bad style, but it's possible to use a ternary operator as an abbreviated if statement: isset($_GET['logout']) ? $session->logout() : $session->extend(); Was this restriction added to make the implementation easier, or because you thought it was a useful feature?switchappears as first token at statement level it will be recognized as statement but ifswitchis in expression context it will be switch-expression. switch ($expr) {case $cond1 => $result1, case $cond2 => $result2, case $cond3 => $result3, default => $default_result,}; // Parse error: syntax error, unexpected '=>' (T_DOUBLE_ARROW) But this is OK. !switch ($expr) {case $cond1 => $result1, case $cond2 => $result2, case $cond3 => $result3, default => $default_result,}; // semicolon is still required because it is an expression
You can omit parenthesized expression which is shortcut toThis is an interesting idea, given that switch(true) is the documented way to do this right now. However, I've always felt switch(true) was rather limited in its advantage over if-elseif. I would prefer a syntax that reduced the boilerplate for: * Different comparisons applied to the same variable/expression, e.g. match($user->getScore()) { case <0 => foo(), case >100 => bar(), default => baz() } * Different values compared against the same expression using the same operator, e.g. match( $exception instanceOf ) { case FooException => handleFoo(), case BarException => handleBar() }switch (true). This change applies to switch statement as well. $v = switch {case $x >= 0 && $x <= 100 => 1, case $x >= 100 && $x <= 200 => 2, default => 3,}; switch {case $x >= 0 && $x <= 100: doSomething1(); break; case $x >= 100 && $x <= 200: doSomething2(); break; default: doNothing(); break;}
You can also useThis seems confusing to me, because it mixes statements and expressions in a rather unusual way. The "return" case in particular seems ambiguous - if $v is visible outside the function, will it have a value assigned to it by the "return" branch, and if so what would that value be? I can imagine more use cases for the "throw" version, and it's reasonably obvious how it would behave, so it might be reasonable to have that one special case.returnandthrowin result expression. I recalled some languages have this feature (but I've forgotten what language). This feature can be very handy and useful in many use cases. $x = 'd'; $v = switch ($x) {case 'a' => 1, case 'b' => 2, case 'c' => return true, default => throw new Exception("'$x' is not supported"),};
Additional feature in the demo patch is the 'type guard' unary operator which is an operator that will perform type check on given value and throwThis is a very interesting feature, although I think what would be even more useful would be syntax to check if something _can_ be cast, i.e. the same check you have here, but as an operator evaluating to boolean. That way, you could write code like this: if ( <int>$_GET['id'] ) { $user = getUser($_GET['id']): } else { echo "Invalid ID provided"; } Which would be equivalent (given a type hint on getUser() and no strict_types declaration) to this, but without needing to use exceptions as flow control: try { getUser($_GET['id']); } catch ( TypeError $e ) { echo "Invalid ID provided"; } Regards, -- Rowan Tommins (né Collins) [IMSoP]TypeErrorwhen type mismatch occurred, otherwise return the value as is. It has the same precedence asnew. $a = 'This is a string'; $v = <int>$a; // TypeError: Value is expected to be int, string given