rfc:match_expression
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revisionNext revisionBoth sides next revision | ||
rfc:match_expression [2020/04/20 18:09] – Describe compilation error when not passing value from block ilijatovilo | rfc:match_expression [2020/04/25 08:11] – Fix list formatting ilijatovilo | ||
---|---|---|---|
Line 93: | Line 93: | ||
<code php> | <code php> | ||
switch ($pressedKey) { | switch ($pressedKey) { | ||
- | case Key::ENTER: | + | case Key::RETURN_: |
save(); | save(); | ||
// Oops, forgot the break | // Oops, forgot the break | ||
Line 172: | Line 172: | ||
</ | </ | ||
- | When you're making use of the result value of the '' | + | Originally this RFC included a way to return a value from a block by omitting the semicolon |
<code php> | <code php> | ||
+ | // Original proposal | ||
$y = match ($x) { | $y = match ($x) { | ||
0 => { | 0 => { | ||
Line 182: | Line 183: | ||
}, | }, | ||
}; | }; | ||
- | </ | ||
- | Not returning a value from a block will lead to a compilation error. | + | // Alternative syntax, <= |
+ | $y = match ($x) { | ||
+ | 0 => { | ||
+ | foo(); | ||
+ | bar(); | ||
+ | <= baz(); | ||
+ | }, | ||
+ | }; | ||
- | <code php> | + | // Alternative syntax, separate keyword |
$y = match ($x) { | $y = match ($x) { | ||
0 => { | 0 => { | ||
foo(); | foo(); | ||
bar(); | bar(); | ||
- | baz(); | + | |
}, | }, | ||
}; | }; | ||
- | //> Match block must return | + | // Alternative syntax, automatically |
+ | $y = match ($x) { | ||
+ | 0 => { | ||
+ | foo(); | ||
+ | bar(); | ||
+ | baz(); | ||
+ | }, | ||
+ | }; | ||
</ | </ | ||
- | This is **not** | + | For the time being using blocks in match expressions that use the return |
<code php> | <code php> | ||
- | function test() { | + | $y = match ($x) { |
- | | + | 0 => {}, |
- | 0 => { | + | }; |
- | foo(); | + | //> Match that is not used as a statement can't contain blocks |
- | bar(); | + | |
- | // baz() will be returned from test(), $y will never be assigned | + | foo(match ($x) { |
- | | + | 0 => {}, |
- | }, | + | }); |
- | }; | + | //> Match that is not used as a statement can't contain blocks |
+ | |||
+ | 1 + match ($x) { | ||
+ | 0 => {}, | ||
+ | }; | ||
+ | //> Match that is not used as a statement can't contain blocks | ||
+ | |||
+ | //etc. | ||
+ | |||
+ | // Only allowed form | ||
+ | match ($x) { | ||
+ | 0 => {}, | ||
} | } | ||
</ | </ | ||
- | ===== Semicolon | + | ===== Optional semicolon for match in statement form ===== |
When using '' | When using '' | ||
Line 228: | Line 253: | ||
</ | </ | ||
- | However, to make the '' | + | However, to make the '' |
<code php> | <code php> | ||
Line 236: | Line 261: | ||
</ | </ | ||
- | This introduces | + | This introduces |
<code php> | <code php> | ||
Line 252: | Line 277: | ||
</ | </ | ||
- | When '' | + | A '' |
- | ===== break/ | + | <code php> |
+ | // These work fine | ||
+ | $x = match ($y) { ... } - 1; | ||
+ | foo(match ($y) { ... } - 1); | ||
+ | $x[] = fn($y) => match ($y) { ... }; | ||
+ | // etc. | ||
+ | </ | ||
+ | |||
+ | This is also how Rust solves this ambiguity((https:// | ||
+ | |||
+ | <code rust> | ||
+ | match true { _ => () } - 1; | ||
+ | |||
+ | // warning: unused unary operation that must be used | ||
+ | // --> src/ | ||
+ | // | | ||
+ | // 2 | match true { _ => () } - 1; | ||
+ | // | ||
+ | // | | ||
+ | </ | ||
+ | |||
+ | Because there was some controversy around this feature it was moved to a secondary vote. | ||
+ | |||
+ | ===== Allow dropping (true) condition ===== | ||
+ | It has been suggested to make no condition equivalent to '' | ||
+ | |||
+ | <code php> | ||
+ | match { | ||
+ | $age >= 30 => {}, | ||
+ | $age >= 20 => {}, | ||
+ | $age >= 10 => {}, | ||
+ | default => {}, | ||
+ | } | ||
+ | |||
+ | // Equivalent to | ||
+ | |||
+ | match (true) { | ||
+ | $age >= 30 => {}, | ||
+ | $age >= 20 => {}, | ||
+ | $age >= 10 => {}, | ||
+ | default => {}, | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | The keyword '' | ||
+ | |||
+ | ===== Miscellaneous ===== | ||
+ | ==== Arbitrary expressions ==== | ||
+ | A match condition can be any arbitrary expression. Analogous to '' | ||
+ | |||
+ | <code php> | ||
+ | match ($x) { | ||
+ | foo() => ..., | ||
+ | $this-> | ||
+ | $this-> | ||
+ | // etc. | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | ==== break/ | ||
Just like with the switch you can use '' | Just like with the switch you can use '' | ||
Line 280: | Line 364: | ||
</ | </ | ||
- | ===== return | + | ==== goto ==== |
+ | Like with the '' | ||
+ | |||
+ | <code php> | ||
+ | match ($a) { | ||
+ | 1 => { | ||
+ | match ($b) { | ||
+ | 2 => { | ||
+ | goto end_of_match; | ||
+ | }, | ||
+ | } | ||
+ | }, | ||
+ | } | ||
+ | |||
+ | end_of_match: | ||
+ | </ | ||
+ | |||
+ | It is not allowed to jump into match expressions. | ||
+ | |||
+ | <code php> | ||
+ | goto match_arm; | ||
+ | |||
+ | match ($b) { | ||
+ | 1 => { | ||
+ | match_arm: | ||
+ | }, | ||
+ | } | ||
+ | |||
+ | //> Fatal error: ' | ||
+ | </ | ||
+ | |||
+ | ==== return | ||
'' | '' | ||
Line 296: | Line 411: | ||
===== Future scope ===== | ===== Future scope ===== | ||
+ | ==== Block expressions ==== | ||
+ | As mentioned above block expressions will be discussed in a separate RFC. We'll also use this opportunity to think about blocks in arrow functions. | ||
+ | |||
==== Pattern matching ==== | ==== Pattern matching ==== | ||
- | I have experimented with pattern matching ((https:// | + | I have experimented with pattern matching ((https:// |
<code php> | <code php> | ||
Line 303: | Line 421: | ||
match ($value) { | match ($value) { | ||
let $a => ..., // Identifer pattern | let $a => ..., // Identifer pattern | ||
+ | let ' | ||
let 0..<10 => ..., // Range pattern | let 0..<10 => ..., // Range pattern | ||
let is string => ..., // Type pattern | let is string => ..., // Type pattern | ||
Line 308: | Line 427: | ||
let Foo { foo: 1, getBar(): 2 } => ..., // Object pattern | let Foo { foo: 1, getBar(): 2 } => ..., // Object pattern | ||
let $str @ is string if $str !== '' | let $str @ is string if $str !== '' | ||
+ | |||
+ | // Algebraic data types if we ever get them | ||
+ | let Ast\BinaryExpr($lhs, | ||
} | } | ||
Line 313: | Line 435: | ||
match (true) { | match (true) { | ||
true => $value ..., // Identifier pattern | true => $value ..., // Identifier pattern | ||
+ | ' | ||
$value >= 0 && $value < 10 => ..., // Range pattern | $value >= 0 && $value < 10 => ..., // Range pattern | ||
is_string($value) => ..., // Type pattern | is_string($value) => ..., // Type pattern | ||
Line 326: | Line 449: | ||
</ | </ | ||
- | While some patterns are significantly shorter (namely the array pattern) code like that is relatively rare. At the moment the argument for such a big language change is pretty weak. If the situation ever changes we can always add pattern matching at a later point in time. | + | ==== Explicit fallthrough |
- | + | Some people have suggested allowing explicit fallthrough to the next arm. This is, however, not a part of this RFC. | |
- | ==== Language wide blocks | + | |
- | While it is possible to make blocks | + | |
<code php> | <code php> | ||
- | $callable = fn() => { | + | match ($x) { |
- | | + | 1 => { |
- | }; | + | foo(); |
+ | | ||
+ | | ||
+ | 2 => { | ||
+ | bar(); | ||
+ | }, | ||
+ | } | ||
+ | |||
+ | // 1 calls foo() and bar() | ||
+ | // 2 only calls bar() | ||
</ | </ | ||
- | However, allowing the same blocks here would allow for two semantically equivalent versions | + | This would require a few sanity checks |
<code php> | <code php> | ||
- | $callable = fn() => { | + | match ($x) { |
- | | + | $a => { fallthrough; |
- | }; | + | |
+ | } | ||
</ | </ | ||
- | |||
- | We would likely want to disallow this. So even here blocks should behave slightly differently. Thus we're better off implementing blocks for arrow functions separately. | ||
- | |||
- | There were no other legitimate use cases I could think of. | ||
===== "Why don't you just use x" ===== | ===== "Why don't you just use x" ===== | ||
Line 371: | Line 498: | ||
</ | </ | ||
- | This code will execute every single " | + | This code will execute every single " |
==== Nested ternary operators ==== | ==== Nested ternary operators ==== | ||
Line 392: | Line 519: | ||
Note that it will continue to work in method names and class constants. | Note that it will continue to work in method names and class constants. | ||
- | |||
- | ===== Proposed PHP Version(s) ===== | ||
- | The proposed version is PHP 8. | ||
===== Proposed Voting Choices ===== | ===== Proposed Voting Choices ===== | ||
- | As this is a language change, a 2/3 majority is required. | + | As this is a language change, a 2/3 majority is required. |
+ | |||
+ | <doodle title=" | ||
+ | * Yes | ||
+ | * No | ||
+ | </ | ||
+ | |||
+ | Secondary | ||
+ | |||
+ | <doodle title=" | ||
+ | | ||
+ | | ||
+ | </ | ||
+ | |||
+ | Secondary | ||
+ | |||
+ | <doodle title=" | ||
+ | * Yes | ||
+ | * No | ||
+ | </ | ||
+ | |||
+ | ==== If you voted no, why? ==== | ||
+ | |||
+ | - Not interested | ||
+ | - I don't want blocks | ||
+ | - Missing return values in blocks | ||
+ | - Missing pattern matching | ||
+ | - Missing explicit fallthrough | ||
+ | - BC break is not acceptable | ||
+ | - Wanted [[https:// | ||
+ | - Other | ||
+ | |||
+ | <doodle title=" | ||
+ | * 1 | ||
+ | * 2 | ||
+ | * 3 | ||
+ | * 4 | ||
+ | * 5 | ||
+ | * 6 | ||
+ | * 7 | ||
+ | * 8 | ||
+ | </ | ||
rfc/match_expression.txt · Last modified: 2020/05/09 15:59 by ilijatovilo