> On Oct 20, 2019, at 7:59 AM, Rowan Tommins <rowan.coll...@gmail.com> wrote:
> 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?

What restriction are you referring to?  The forced `default` or the semi-colon 
being required?

If `default`, I concur.

> I've always felt switch(true) was rather limited in its advantage over 
> if-elseif.

I would much prefer to use a switch for multiple, mutually exclusive cases no 
matter what how complex the expression is because with a switch the cases 
expressions line up vertically. With `if` and `else if` it is harder to 
vertically eyeball the different mutually exclusive cases.

With that, I would even argue that we deprecate `else`.  Except I know that 
would be a battle so I wouldn't actually suggest it. :-)

> 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() }

However, I would very much like to see both of those options, for switch 
expressions and switch statements.

It is "syntax sugar," but IMO[1] programming languages evolve best when they 
recognize commonly used-patterns and then apply syntax sugar to make those 
patterns more obvious, less error prone and easier to reason about.

Further, your introduction of a `match` keyword here is intriguing, and we 
could probably leverage it for other use cases. Maybe as an alternate to switch 
statements that do not require `break`s?

>> $x = 'd';
>> $v = switch ($x) {
>>     case 'a' => 1,
>>     case 'b' => 2,
>>     case 'c' => return true,
>>     default => throw new Exception("'$x' is not supported"),
>> };
> 
> 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?

It should have its prior value, since the expression did not complete.  

Alternately we could choose to always assign it null on return or break.

But how often will we have this use-case?  Only for global variables, which 
hopefully will eventually become extinct in userland code.

> 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";
> }

+1 to use for can-cast checking.  In GoLang this is called a type assertion and 
is thus similar:

if id,ok = get['id'].(string); ok {
   $user = get['id'].(string);
} else {
   echo "Invalid ID provided";
}

It would be super nice for PHP to have an equivalent. 

That said, we should almost be able to do both, and just let PHP throw an error 
if there is a problem. This would be useful if you know 100% that the code 
won't fail because of the code that came before it:

if ( is_numeric($_GET['id'] ?? 0 ) ) {
    $id = intvar($_GET['id'] ?? 0);
     $user = getUser(<int>$id):
}
 

-Mike
[1] https://mikeschinkel.me/2019/in-defense-of-syntactic-sugar/ 
<https://mikeschinkel.me/2019/in-defense-of-syntactic-sugar/>

Reply via email to