Re: Re: [DISCUSSION] Match expression
| From: | Andrea Faulds | Date: | Tue, 14 Apr 2020 20:48:23 +0000 |
| Subject: | Re: Re: [DISCUSSION] Match expression | ||
| References: | 1 2 3 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-109643@lists.php.net to get a copy of this message | ||
Hi Ilija,
Ilija Tovilo wrote:
Well, I don't think we have any other expressions that are also statements with very slightly different syntax, and in this RFC you propose that the expression and statement forms have different behaviour (expression doesn't support blocks) despite looking the same. So it's neither consistent with other statements and expressions, nor is it internally consistent.I share others' concern that it is inconsistent with PHP's existing statementsCan you elaborate on what exactly the concerns are?
We already have a limited kind of pattern matching in PHP, destructuring assignment for arrays. You can use it on the left-hand side of any assignment, and also inIt is a shame you don't suggest taking this opportunity to add pattern matching.My main concern here is just complexity. There's so much to consider. We need to think well about each pattern, how it should work, what it should look like, how it should be implemented, etc. Furthermore pattern matching usually isn't restricted to the match expression. There's often pattern matching forif,while,foreach, function params, normal assignment, etc. So I don't think it should be mixed with this RFC. IMO if we implement pattern matching we should make it available for all of these cases.
foreach. This pattern can even fail to match, but you get an E_NOTICE instead of a Throwable.
It might be nice to have it in some other places, but it isn't necessary. Haskell itself only has it in function definitions, assignments and case expressions IIRC, and the former two uses are essentially sugar over use of case anyway.
Why not take what we have here and support it in match too, but with slightly stricter rules so that cases that would otherwise trigger an E_NOTICE lead to choosing a different branch? It would make both our existing pattern-matching and match more powerful! Consider interacting with some JSON API:
match (json_decode($response)) {
['error' => ['code' => $code, 'msg' => $msg] => {
throw new Exception($msg, $code);
},
['result' => $result] => {
return $result;
},
// No default, so if the JSON doesn't fit this expected format, an error is thrown! :)
}
This is just a quick example that came to mind, which doesn't really use the full potential available here.
Another kind of existing pattern matching is arguably catch in exception handling, so maybe we could also have SomeClass $obj as a pattern, though that syntax would lead to questions of whether things like ?SomeClass, int and SomeClass|SomeClass2 should work…
It would be a bit surprising if you are new to theUsing a keyword prefix (e.g.I personally don't think so. Consider this case:let) in future means we end up with two kinds of arm (one with === behaviour, one with pattern-matching behaviour), but wouldn't it be simpler to have just one?$x = 10; $y = 20; // This variable is unused match ($x) { $y => { // Always true echo $y; // Outputs 10 }, }$yis an identifier pattern and it always matches and assigns the given value to the variable. This is rather confusing. A keyword likeletwould make it more obvious that you're using a pattern. I'd also suspect that it's more common to pass expressions to the lhs of a match statement than patterns so it makes sense that this is the default.
match statement and had not used something similar in another language, indeed. But how often do people use switch with cases like this that don't use a constant or literal value? It's not even supported in some popular languages like C, and in the rare case that you need this behaviour, a guard can be used:
match ($x) {
default if ($x === $y) => {
echo $y;
}
}
By the way, having one kinds of arm would mean you don't have to think about the two kinds when reading code like this:
match ($x) {
$y => {
// …
},
let $y => {
// …
},
}
Also, imagine you want to equate multiple dynamic values with each other:
$x = ...;
$y = ...;
$z = ...;
match ($x) {
$y => ...,
$z => ...,
}
// If we only have pattern matching
match (true) {
true if $x === $y => ...,
true if $x === $z => ...,
}
True, that is less elegant. But when would you need to do that?
Thanks,
Andrea