Hi Rowan Thank you for your reply.
Was this restriction added to make the implementation easier, or because > you thought it was a useful feature? > This is not a restriction but a result of implementation workarounds. Let's see: switch ($x) { case 1: echo "ONE\n"; break; case 2: echo "TWO\n"; break; } vs switch ($x) { case 1 => print "ONE\n", case 2 => print "TWO\n", }; You can recognize the difference of those by looking for `=>` right? But the parser generator (bison) cannot do that in LR mode (it maybe can in GLR mode but I'm sure that would be unacceptable due to performance losses/more memory usage). So workarounds have to be used. I did it by simply return different tokens from the lexer base on previous token before `switch`. https://github.com/webdevxp/php-src/blob/switch-expression/Zend/zend_language_scanner.l#L1460 https://github.com/webdevxp/php-src/blob/switch-expression/Zend/zend_language_scanner.l#L1247 And use that different tokens to define rules in the parser definition so it won't have any shift/reduce conflicts. https://github.com/webdevxp/php-src/blob/switch-expression/Zend/zend_language_parser.y#L443 https://github.com/webdevxp/php-src/blob/switch-expression/Zend/zend_language_parser.y#L1107 * Different comparisons applied to the same variable/expression, e.g. > match($user->getScore()) { case <0 => foo(), case >100 => bar(), default > => baz() } I'd thought about that feature too. But since I also introduced type guard operator which uses `<` token it would have parser conflicts and simple workarounds cannot apply. $v = switch ($x) { case < <int>$y => 1, // shift/reduce conflict here }; But if type guard was removed or changed to use another token like `(:int)` that feature would be easy to implement because currently `ZEND_CASE` opcode has `extended_value` unused so we can use it to store operator data. Cheers > > On Sun, Oct 20, 2019 at 9:15 PM Rowan Tommins <rowan.coll...@gmail.com> wrote: > 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, if > > `switch` appears as first token at statement level it will be recognized > as > > statement but if `switch` is 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 > > > This 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? > > > > You can omit parenthesized expression which is shortcut to `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; > > } > > > This 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() } > > > > > You can also use `return` and `throw` in 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"), > > }; > > > This 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. > > > > > 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 > throw > > `TypeError` when type mismatch occurred, otherwise return the value as > is. > > It has the same precedence as `new`. > > > > $a = 'This is a string'; > > $v = <int>$a; // TypeError: Value is expected to be int, string given > > > This 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] > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: http://www.php.net/unsub.php > >