Re: [PHP-DEV] [VOTE] match expression
On Thu, 30 Apr 2020 at 13:18, Ilija Tovilo wrote: > There are three potential use cases for language wide block expressions. > > 1. Match expressions > 2. Arrow functions > 3. Everything else > > The problem is that they all have slightly different semantics. > [...] > I don't think that's actually true. If I'm understanding you right, you're concerned about two things: * Blocks which don't have a return value where one is expected / required. * Blocks which do have a return value where one is not expected. The language already has an established convention for both cases: a function with no return statement evaluates to NULL in expression context, and a function with a return value can be used in statement context and the result discarded. I see no immediate reason block expressions couldn't use the same rule. > $y = match ($x) { > 1 => {}, // Error, this does require a return value > }; > This could evaluate the block to null, and thus be equivalent to: $y = match ($x) { 1 => null, }; $x = fn() => {}; // This is fine, the function returns null > $x = fn(): ?int => {}; // Uncaught TypeError: Return value of > {closure}() must be of the type int or null, none returned > I had no idea that was an error; I guess it's the counterpart to ": void" - a style check rather than an actual return type check. But I don't see a particular problem with a short closure giving the same error as the equivalent named function (function foo(): ?int {}) so there doesn't seem to be anything extra to define here. > $x = fn() => { > foo(); > bar(); > <= baz(); // Why should we allow this? You can just use return > }; > Because right now, you *can't* use return; there are no block bodied short closures. If we did allow "return" here, there's no *fundamental* reason not to also allow it in a match expression, meaning "return this as the value of the match expression" (we might not *want* to reuse the keyword, but we *could*). > // All of these are errors, return value is required > $x = {}; > foo({}); > {} + 1; > // etc. > They would be evaluated as empty statements, and "return" null: $x = null; foo(null); null + 1; > It's also highly questionable whether use case 3 is actually very > useful at all because PHP doesn't have block scoping and all the inner > variables will leak out into the outer scope. [...] > An additional complication is that blocks already exist as "statement > list" statements > We could potentially solve both of these by introducing a new syntax which made something explicitly a block expression. I'm not sure what the keyword would be; "do" is already used, and "eval" has bad connotations, so I'll use "block" as a straw man to demonstrate. // block expression as RHS of assignment $this->foo = block { $bar = new Bar(); $foo = new Foo(); $foo->bar = $bar; return $foo; }; // $this->foo has been assigned, $bar and $foo are no longer in scope // block expression as arm of match expression $y = match ($x) { 1 => block { foo(); return bar(); }, } // if $x===1, foo() is executed, then $y gets the result of bar() // block expression as result of short closure $f = fn($x) => block { foo($x); bar($x); }; $f(); // even if the expression result isn't used, the scoping could apply if ( foo() ) block { $x = 1; }; // $x is not defined here // note trailing semi-colon, for the same reason you need one after a standard anonymous function definition // the above is actually equivalent to this: if ( foo() ) { block { $x = 1; }; } I don't know if I *like* this idea, but it would be a consistent language-wide implementation of the concept with minimal compatibility impact. It's not that black and white. I work in a lot of legacy projects that > could benefit from match expressions but it's simply not realistic to > refactor every single switch statement that contains more than a one > liner. > To use Larry's codenames, would those specifically benefit from "rustmatch" (evaluating the switch to an expression) or from "switchng" (a stricter switch statement)? I'd be interested to see a real-life example where you'd want both the match to evaluate to a value, and the arms to contain more than one statement. Regards, -- Rowan Tommins [IMSoP]
Re: [PHP-DEV] [VOTE] match expression
Hi someniatko I think you have a firm grasp of the key issues but I don't agree with your conclusion. > Problem no. 2 could be addressed by > allowing "complex" expressions consisting of, potentially, few > statements, language-wide, solving the issue both for short closures > and for `match` I have analysed this approach a while back and I don't think there is a universal and elegant solution. I have mentioned this in the list but never fully explained it. Upfront, when I say "block expression" I'm talking about a block `{}` that contains any number of statements with some terminating expression that will be returned. $x = { foo(); bar(); <= baz(); }; // Result of baz() is now assigned to $x There are three potential use cases for language wide block expressions. 1. Match expressions 2. Arrow functions 3. Everything else The problem is that they all have slightly different semantics. 1. A block expression in a match arm would require a return value depending if the outer match return value is used match ($x) { 1 => {}, // Doesn't require a return value } $y = match ($x) { 1 => {}, // Error, this does require a return value }; 2. Arrow functions would only require a return value if the function has an explicit return type (to be consistent with functions and normal closures) $x = fn() => {}; // This is fine, the function returns null $x = fn(): ?int => {}; // Uncaught TypeError: Return value of {closure}() must be of the type int or null, none returned It's very questionable whether we even want to allow block-style return values in arrow functions. $x = fn() => { foo(); bar(); <= baz(); // Why should we allow this? You can just use return }; 3. For every other expression the return value of the block would always be required // All of these are errors, return value is required $x = {}; foo({}); {} + 1; // etc. It's also highly questionable whether use case 3 is actually very useful at all because PHP doesn't have block scoping and all the inner variables will leak out into the outer scope. The only potential improvement here is readability. $this->foo = { $bar = new Bar(); $foo = new Foo(); $foo->bar = $bar; <= $foo; // Or whatever block syntax }; // $bar still exists here but it's a little // more obvious it shouldn't be used anymore No matter if statement blocks become a language wide feature or not, we won't get around handling these cases slightly differently. An additional complication is that blocks already exist as "statement list" statements: https://github.com/php/php-src/blob/php-7.4.5/Zend/zend_language_parser.y#L427 function foo() { { // This is a "statement list" statement } if (true) { // This is also a "statement list" statement } } Whether we'd also (a) convert these to block expressions or (b) keep "statement list" statements and block expressions separate is unclear. If we do convert "statement list" statements to block expressions we'll have to make the semicolon of a statement level block expression optional to avoid BC breaks. I received a lot of criticism for the same thing in this RFC. If we don't convert "statement list" statements to block expressions empty blocks won't become valid syntax in match arms and we'll have to explicitly allow them in the grammar (which is what this RFC is doing right now). (a) { // Blocks are expressions now, expressions at a statement level require a semicolon. // The semicolon must stay optional or we'll have a BC break. } (b) { // This is still a statement } match ($x) { 1 => { // Also a statement which means it can't be used here unless we explicitly allow expressions AND "statement list" statements }, } To summarize, blocks are only really useful in match arms and arrow functions and behave differently even in just these two cases. While I wouldn't mind language wide blocks it isn't the universally elegant solution people make it up to be. This is the best explanation I could give. Let me know if it's still not completely clear. > IMO this covers vast majority of use-cases of the PHP statements. Not really, if you look at Nikita's analysis of 50 random switch statements. It only covers ~40%. > IMO a good language should enforce better quality. The main issue I have with this is that good code quality doesn't look the same to everybody. Even programmers with decades of experience will disagree on fundamentals. I'd be very hesitant to say that moving two lines into a function is an improvement, especially if it's only called once. The only thing it does is disrupt the reading flow. match ($x) { 1 => { foo(); bar(); }, } vs. match ($x) { 1 => fooAndBar(), }; function fooAndBar() { foo(); bar(); } I don't think using a closure for all of these cases is a viable solution. > Also, those people who would benefit > from less boilerplate which match in expression-only form
Re: [PHP-DEV] [VOTE] match expression
meh, sorry, i top-posted by incident. I did not have the e-mails to respond to (because i have just subscribed to the ML), therefore i thought if i post with the same subject, my mail will add up to the same thread. -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] [VOTE] match expression
Hi! I am quite new to the internals list, but wanted to say a word, to maybe lit some light on the discussion, for you to be able to look at it from slightly another angle. I have noticed this whole thread arguing whether it is required or not to support `match` keyword in an if-else-ish control-flow manner: in other words, support not only expressions in the `match` branches, but also arbitrary statements. As we know, each PHP expression can be used as a statement. We also know that large subset of practically used statements (function call, variable assignment) can be implemented in expression form. This subset also tends to enlarge: recently throwing an exception became expressible in expression form. This means we can write code like this: ``` match($state) { State::VALID => processFurther(), State::PENDING => $isPending = true, State::INVALID => throw new \RuntimeException(), }; ``` IMO this covers vast majority of use-cases of the PHP statements. The cases which are not covered are: 1) statements which cannot be expressed as expressions: `echo`, `unset`. 2) control flow which requires usage of more than one statement, e.g. assigning two variables, or calling two functions with void return type one after another one etc. I would like to emphasize that this problem is the same as short closures problem, and should be treated at the same time. Problem no. 1 could be solved by allowing statements like `unset` to be used in expression form, if it's feasible. Problem no. 2 could be addressed by allowing "complex" expressions consisting of, potentially, few statements, language-wide, solving the issue both for short closures and for `match`, if it is really needed though. Anyway it is possible to use in-place old-school closure as a temporary workaround. > I think that sums it up nicely. Let's also remember that these are popular, well maintained repositories and probably don't reflect the average code quality very well. IMO a good language should enforce better quality. Especially when we talk about new language constructs. Short closures already enforce SRP, at least in closures world. Also, those people who would benefit from less boilerplate which match in expression-only form provides, are usually the people who care about code quality. Those who you mention as "average code quality" would not bother with new syntax at all and would still prefer old-school switch to do whatever level of entanglement they had used to. If, though, you insist on match to completely replace old switch, as well as short closures to replace traditional ones, you may want to consider to solve "complex expression" problem once for both of them, and move this out of scope of this RFC. This will allow for gradual improvement of the language, from which both parties will benefit: those who want to write clean code (which is usually split up in functions such that match can be used straight away with only one expression per arm), and those who use complex logic in switches - will be able to do the same in match, but later, when "complex expressions" are implemented. someniatko -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] [VOTE] match expression
On 29/04/2020 01:26, Larry Garfield wrote: To that end, I'm going to refer to them as rustmatch (an expression that only supports expressions and returns things; basically a fancier alternative to ternary) and switchtng (a procedural branching statement that is basically switch but with the lessons of the 40 years since C switch was invented, which PHP blindly inherited) to avoid privileging one or the other. I like the codenames. :) Thinking about it, I think the "switchng" syntax can be even more conservative. The RFC lists four issues with switch, of which three would be applicable to a "switchng" RFC: 1. Type coercion 2. Fallthrough 3. Inexhaustiveness For #1, the only thing we need is some way to opt into "strict mode" on the switch statement, and have the comparisons handled by === rather than ==. That could be as simple as writing "switch strict" instead of "switch". For #2, the problem is that fallthrough is implicit where no "break" is present, so what if we just said that reaching another "case" statement was a runtime error in a switchng statement? That would mean any existing switch statement that didn't use fallthrough could be "upgraded" without changing its body at all. We could allow multiple case labels with no statements between, allowing for the common scenario of multiple conditions running identical code. Alternatively (or as a separate enhancement) we could allow comma-separated lists in case blocks (on both normal switch and switchng). For other cases of fallthrough, we could add a new keyword (or recycle "continue") to explicitly go to the next case. That could even be left to "Future Scope", because anyone wanting it can always "downgrade" to the version with implicit fallthrough. Finally, #3 can be part of the same "strict mode", with one of two behaviours: a) Make a switchng with no "default:" clause a compile-time error b) Make a switchng which doesn't match any case a run-time error, effectively adding an implicit clause of "default: throw new Error(); break;" So our shiny new "switchng" statement would look ... exactly the same as a normal switch statement, but with one new keyword, and the ability to throw two new errors. Regards, -- Rowan Tommins (né Collins) [IMSoP] -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] [VOTE] match expression
On Wed, Apr 29, 2020, at 1:41 AM, Ilija Tovilo wrote: > > Or for that matter... is anyone actually using that syntax in the wild, or > > is it hypothetical? > > It's quite common in C (you can't declare variables directly in a > switch case) so I'd guess it would be used at least by some people in > PHP. > > The worst part is that your code wouldn't throw, it would just start > behaving differently. > > Looking at grep.app you'll find quite a few of them. > https://grep.app/search?q=%3A%20%7B&filter[lang][0]=PHP > (Note that searching with regex won't work as that only shows a very > small subset of results.) > > Ilija Well, poopy. I still think splitting the RFC in half (rust-style match and Go-style switch) is the correct way forward, whatever the syntax particulars. --Larry Garfield -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] [VOTE] match expression
> Or for that matter... is anyone actually using that syntax in the wild, or is > it hypothetical? It's quite common in C (you can't declare variables directly in a switch case) so I'd guess it would be used at least by some people in PHP. The worst part is that your code wouldn't throw, it would just start behaving differently. Looking at grep.app you'll find quite a few of them. https://grep.app/search?q=%3A%20%7B&filter[lang][0]=PHP (Note that searching with regex won't work as that only shows a very small subset of results.) Ilija -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] [VOTE] match expression
On Tue, Apr 28, 2020 at 6:58 PM Larry Garfield wrote: > > On Tue, Apr 28, 2020, at 7:37 PM, Levi Morrison via internals wrote: > > > One issue that was discussed a few weeks ago, and led to the current > > > syntax, was too many variations within the switch syntax; of course, > > > trying to do it all in one syntax is perpetuating that problem. However, > > > I think Rowan has suggested a syntax that may be sufficiently > > > self-documenting. To wit, independent of rustmatch (above): > > > > > > switch ($foo) { > > > case 1: { > > > Many statements here. > > > } > > > case 2: { > > > Many statements here. > > > } > > > } > > > > > > The curly braces are already understood by most PHPers to mean "a block > > > of statements", and so it's a logical jump in this case. As Rowan > > > suggests, the {} imply a break. To keep it simple we should probably not > > > allow mixing and matching in a single switch. Either list-style (break > > > required) or {}-style (break implied). > > > > > > That handles break; > > > > Sadly, it doesn't. That code is valid today: > > > > > $foo = 1; > > switch ($foo) { > > case 1: { > > echo "1\n"; > > } > > case 2: { > > echo "2\n"; > > } > > } > > ?> > > > > Which outputs: > > 1 > > 2 > > ... Well, crap. It just can't be easy, can it... > > Would it be too context-sensitive to have the {} version only work in strict > switch? > > Or for that matter... is anyone actually using that syntax in the wild, or is > it hypothetical? Viz, if the behavior of that changed in 8.0 (a major > release), would that even break anything? Even 7.4 has a couple of "the > behavior changed but seriously who was using this anyway?" points in it. > Could we get away with just changing it for 8.0? > > I'm not sure if Nikita's "check the top 1000" script could handle something > that subtle. > > --Larry Garfield > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: http://www.php.net/unsub.php I am confident it was used in a former employer's codebase, which is how I immediately knew it was valid. My memory is too fuzzy to remember anything more than it was used, unfortunately. -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] [VOTE] match expression
On Tue, Apr 28, 2020, at 7:37 PM, Levi Morrison via internals wrote: > > One issue that was discussed a few weeks ago, and led to the current > > syntax, was too many variations within the switch syntax; of course, trying > > to do it all in one syntax is perpetuating that problem. However, I think > > Rowan has suggested a syntax that may be sufficiently self-documenting. To > > wit, independent of rustmatch (above): > > > > switch ($foo) { > > case 1: { > > Many statements here. > > } > > case 2: { > > Many statements here. > > } > > } > > > > The curly braces are already understood by most PHPers to mean "a block of > > statements", and so it's a logical jump in this case. As Rowan suggests, > > the {} imply a break. To keep it simple we should probably not allow > > mixing and matching in a single switch. Either list-style (break required) > > or {}-style (break implied). > > > > That handles break; > > Sadly, it doesn't. That code is valid today: > > $foo = 1; > switch ($foo) { > case 1: { > echo "1\n"; > } > case 2: { > echo "2\n"; > } > } > ?> > > Which outputs: > 1 > 2 ... Well, crap. It just can't be easy, can it... Would it be too context-sensitive to have the {} version only work in strict switch? Or for that matter... is anyone actually using that syntax in the wild, or is it hypothetical? Viz, if the behavior of that changed in 8.0 (a major release), would that even break anything? Even 7.4 has a couple of "the behavior changed but seriously who was using this anyway?" points in it. Could we get away with just changing it for 8.0? I'm not sure if Nikita's "check the top 1000" script could handle something that subtle. --Larry Garfield -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] [VOTE] match expression
> One issue that was discussed a few weeks ago, and led to the current syntax, > was too many variations within the switch syntax; of course, trying to do it > all in one syntax is perpetuating that problem. However, I think Rowan has > suggested a syntax that may be sufficiently self-documenting. To wit, > independent of rustmatch (above): > > switch ($foo) { > case 1: { > Many statements here. > } > case 2: { > Many statements here. > } > } > > The curly braces are already understood by most PHPers to mean "a block of > statements", and so it's a logical jump in this case. As Rowan suggests, the > {} imply a break. To keep it simple we should probably not allow mixing and > matching in a single switch. Either list-style (break required) or {}-style > (break implied). > > That handles break; Sadly, it doesn't. That code is valid today: Which outputs: 1 2 -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] [VOTE] match expression
On Tue, Apr 28, 2020, at 10:31 AM, Rowan Tommins wrote: > On Tue, 28 Apr 2020 at 16:10, Bob Weinand wrote: > > > I think you should first think about why the "case" needs to exists at > > all. In particular it exists to distinguish goto labels from the case > > expressions in switch. With match, match restricting statements (and thus > > goto labels) into { brackets }, it now is not necessary to do such a > > distinction and we can get rid of the extra token. > > > > > That may be obvious if you're used to writing parsers, but to users, the > case keyword is simply how switch statements work. Removing it just makes > the new statement look less familiar and isn't justified by the aims stated > in the RFC. > > > > > "=>" is logical as well, we use the return value of the expressions (see > > fn() and array syntax), the colon is exclusively used for pure statement > > boundaries. > > > > > You've missed the context of my e-mail: I was explicitly discussing a > hypothetical syntax that *doesn't* resolve to a value, and where the colon > *is* introducing a statement not an expression. > > > > > The comma is necessary for the expression syntax at least (consider > > match($a) { 1 => 2 + 2 + 2 => 3 } - is this now match($a) { 1 => 2, (2 + > > 2) => 3 } or match ($a) { 1 => (2 + 2), +2 => 3 } ?) You may argue to make > > it optional behind a statement block though. > > > > Again, expressions are explicitly out of scope for this thought experiment. > As such, the result of every case is delimited either by a closing brace or > a semi-colon, and the above example is simply a syntax error. > > > As I've said many times now, I really like the match expression, with the > current syntax, as a pure expression. I was explicitly addressing the > question of why I think a straight-forward switch replacement would not > look the same if we weren't trying to squeeze two features into one syntax. > > Regards, > -- > Rowan Tommins > [IMSoP] I agree that there seems to be two entirely different problem spaces being smushed together here, which is creating a problem (both for the code and for the discussion). Which... suggests we really should try to split them up. To that end, I'm going to refer to them as rustmatch (an expression that only supports expressions and returns things; basically a fancier alternative to ternary) and switchtng (a procedural branching statement that is basically switch but with the lessons of the 40 years since C switch was invented, which PHP blindly inherited) to avoid privileging one or the other. Based on the current RFC voting, it seems like there's strong interest in rustmatch, using the syntax currently proposed: $expressionResult = match ($condition) { 1, 2 => foo(), 3, 4 => bar(), default => baz(), }; I'm calling this "rustmatch" because its semantics and syntax are largely borrowed from Rust's match expression (https://aminb.gitbooks.io/rust-for-c/content/control_flow/index.html). (Yes, Rust supports multi-line expressions but it does all over the place, which is a separate issue.) The other is what, I think, Ilja was originally trying to do, which is a more Go-style switch (https://gobyexample.com/switch) than a C-style switch. That is, still a procedural construct but less bug-prone. One issue that was discussed a few weeks ago, and led to the current syntax, was too many variations within the switch syntax; of course, trying to do it all in one syntax is perpetuating that problem. However, I think Rowan has suggested a syntax that may be sufficiently self-documenting. To wit, independent of rustmatch (above): switch ($foo) { case 1: { Many statements here. } case 2: { Many statements here. } } The curly braces are already understood by most PHPers to mean "a block of statements", and so it's a logical jump in this case. As Rowan suggests, the {} imply a break. To keep it simple we should probably not allow mixing and matching in a single switch. Either list-style (break required) or {}-style (break implied). That handles break; the other problems listed in the RFC for switch are: * weak comparison * Inexhaustive * No return The no-return is only an issue for the expression-centric approach, which belongs to rustmatch, and thus in a split approach is off topic. If you want multi-prong branching that evaluates to a returned value... use the rustmatch option and be done with it, go away. For the other two, would a simple "strict" keyword be acceptable to people? The net result being: switch strict ($foo) { case 1: { Many statements here. } case 2: { Many statements here. } } That does a strict type comparison on $foo, triggers a warning/error/whatever if nothing matches (default is still supported of course), and the curly braces replace break. It can NOT return anything, but that's OK, because it's a flow control construct, not an expression. Never the twain shall meet.
Re: [PHP-DEV] [VOTE] match expression
On Tue, 28 Apr 2020 at 16:10, Bob Weinand wrote: > I think you should first think about why the "case" needs to exists at > all. In particular it exists to distinguish goto labels from the case > expressions in switch. With match, match restricting statements (and thus > goto labels) into { brackets }, it now is not necessary to do such a > distinction and we can get rid of the extra token. > That may be obvious if you're used to writing parsers, but to users, the case keyword is simply how switch statements work. Removing it just makes the new statement look less familiar and isn't justified by the aims stated in the RFC. > "=>" is logical as well, we use the return value of the expressions (see > fn() and array syntax), the colon is exclusively used for pure statement > boundaries. > You've missed the context of my e-mail: I was explicitly discussing a hypothetical syntax that *doesn't* resolve to a value, and where the colon *is* introducing a statement not an expression. > The comma is necessary for the expression syntax at least (consider > match($a) { 1 => 2 + 2 + 2 => 3 } - is this now match($a) { 1 => 2, (2 + > 2) => 3 } or match ($a) { 1 => (2 + 2), +2 => 3 } ?) You may argue to make > it optional behind a statement block though. Again, expressions are explicitly out of scope for this thought experiment. As such, the result of every case is delimited either by a closing brace or a semi-colon, and the above example is simply a syntax error. As I've said many times now, I really like the match expression, with the current syntax, as a pure expression. I was explicitly addressing the question of why I think a straight-forward switch replacement would not look the same if we weren't trying to squeeze two features into one syntax. Regards, -- Rowan Tommins [IMSoP]
Re: [PHP-DEV] [VOTE] match expression
> Am 28.04.2020 um 12:48 schrieb Rowan Tommins : > > On Tue, 28 Apr 2020 at 11:19, Ilija Tovilo wrote: > >>> for the control-flow statement, it feels awkward and not in >>> keeping with the rest of the language. If they were separate proposals, >> the >>> statement would probably end up looking very different. >> >> Can you elaborate? If I made a proposal exclusively for match >> statements the syntax would be exactly equivalent. >> > > > If we take away the expression part, the proposal would be to replace this > switch statement: > > switch ( $expr ) { > case 1: > case 2: > statement; > break; > default: > statement; > break; > } > > With this match statement: > > match ( $expr ) { > 1, 2 => { > statement; > }, > default => { > statement; > }, > } > > The extra set of {} inside looks a little odd, but is a reasonable way to > remove the implicit fallthrough. However, the other changes seem to just be > arbitrarily new syntax: > > * No "case" keyword > * => instead of : > * commas between statement blocks > > If the motivation is simply to fix the current switch statement, why not > keep the syntax more familiar? > > match ( $expr ) { > case 1, 2: { > statement; > } > default: { > statement; > } > } > > The colon looks unnecessary next to the opening brace, but if we keep it, > the braces could be optional like they are in an if statement: > > match ( $expr ) { > case 1, 2: statement; > default: statement; > } > > Note that this wouldn't suffer the problems of accidentally running code > that you get with one-line if statements, because the following could > simply be a syntax error: > > match ( $expr ) { > case 1, 2: statement; anotherStatement; > default: statement; > } > > > That syntax doesn't lend itself as well to being used as an expression, but > I'm not convinced making one syntax work for both use cases is the right > goal given the compromises it requires. > > > Regards, > -- > Rowan Tommins > [IMSoP] Hey Rowan, I think you should first think about why the "case" needs to exists at all. In particular it exists to distinguish goto labels from the case expressions in switch. With match, match restricting statements (and thus goto labels) into { brackets }, it now is not necessary to do such a distinction and we can get rid of the extra token. "=>" is logical as well, we use the return value of the expressions (see fn() and array syntax), the colon is exclusively used for pure statement boundaries. The comma is necessary for the expression syntax at least (consider match($a) { 1 => 2 + 2 + 2 => 3 } - is this now match($a) { 1 => 2, (2 + 2) => 3 } or match ($a) { 1 => (2 + 2), +2 => 3 } ?) You may argue to make it optional behind a statement block though. Bob -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] [VOTE] match expression
On Tue, 28 Apr 2020 at 11:19, Ilija Tovilo wrote: > > for the control-flow statement, it feels awkward and not in > > keeping with the rest of the language. If they were separate proposals, > the > > statement would probably end up looking very different. > > Can you elaborate? If I made a proposal exclusively for match > statements the syntax would be exactly equivalent. > If we take away the expression part, the proposal would be to replace this switch statement: switch ( $expr ) { case 1: case 2: statement; break; default: statement; break; } With this match statement: match ( $expr ) { 1, 2 => { statement; }, default => { statement; }, } The extra set of {} inside looks a little odd, but is a reasonable way to remove the implicit fallthrough. However, the other changes seem to just be arbitrarily new syntax: * No "case" keyword * => instead of : * commas between statement blocks If the motivation is simply to fix the current switch statement, why not keep the syntax more familiar? match ( $expr ) { case 1, 2: { statement; } default: { statement; } } The colon looks unnecessary next to the opening brace, but if we keep it, the braces could be optional like they are in an if statement: match ( $expr ) { case 1, 2: statement; default: statement; } Note that this wouldn't suffer the problems of accidentally running code that you get with one-line if statements, because the following could simply be a syntax error: match ( $expr ) { case 1, 2: statement; anotherStatement; default: statement; } That syntax doesn't lend itself as well to being used as an expression, but I'm not convinced making one syntax work for both use cases is the right goal given the compromises it requires. Regards, -- Rowan Tommins [IMSoP]
Re: [PHP-DEV] [VOTE] match expression
Hi Nikita Thank you for your analysis. That's something I should've done as part of the RFC. I can only share my personal motivation for creating this RFC. Some people will disagree. > Is match intended as a replacement for switch? To me, match is primarily a switch alternative with safer semantics. While it is very nice that match evaluates to the executed arm I think statement matches would be more common and more useful. Your analysis seems to align with that. > If we limit match to returning simple expressions > only, is it still a viable replacement for switch? I don't think so. Of course, some people might argue that the switch is fine and doesn't need a replacement which is an entirely valid viewpoint. However, that would directly contradict most of the arguments made in the RFC. If the switch is fine adding another alternative with different semantics is questionable. If the issues listed in the RFC are valid IMO this RFC only makes sense supporting blocks. > Of the switches I looked at, 31 cannot use match in single-expression form, > while 21 can. I think that sums it up nicely. Let's also remember that these are popular, well maintained repositories and probably don't reflect the average code quality very well. Let me also address Rowans comment: > Why does it need to *replace* anything? Introducing switch to a language > isn't usually considered a replacement for if-elseif-else, even though the > usage overlaps heavily. The if statement doesn't have (most of) the issues stated in the RFC. Match is a direct response to the flaws of the switch. Without blocks match won't actually be usable in most of these cases and you'll be stuck with switch and its flaws. Again, you can argue the switch doesn't have flaws but then the whole RFC doesn't make any sense. > for the control-flow statement, it feels awkward and not in > keeping with the rest of the language. If they were separate proposals, the > statement would probably end up looking very different. Can you elaborate? If I made a proposal exclusively for match statements the syntax would be exactly equivalent. Ilija -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] [VOTE] match expression
On Tue, 28 Apr 2020 at 09:48, Nikita Popov wrote: > Many people in the voting thread are calling for supporting match > expressions only (without support for either statement form, or support for > block expressions). The RFC motivates the match construct as an improved > replacement for switch, which is type-safe, exhaustive and has no > fallthrough gotchas. If we limit match to returning simple expressions > only, is it still a viable replacement for switch? [...] > Is match intended as a replacement for switch? Or is intended to replace > the ternary operator? Two thoughts on this: 1) Why does it need to *replace* anything? Introducing switch to a language isn't usually considered a replacement for if-elseif-else, even though the usage overlaps heavily. Instead, it's seen as an extra tool in the chest, with its own strengths and weaknesses. I think it's better to focus on what the use cases are, rather than how they'd currently be written. In other words, the fact that it's not a straight replacement for switch may be a feature, not a bug. 2) As a thought experiment, imagine splitting the current proposal into two: a new conditional expression, and a new control-flow statement. To me, the syntax currently proposed works really nicely for the conditional expression; for the control-flow statement, it feels awkward and not in keeping with the rest of the language. If they were separate proposals, the statement would probably end up looking very different. That's why it feels more natural to suggest dropping the statement and keeping the expression than the other way around. Regards, -- Rowan Tommins [IMSoP]
Re: [PHP-DEV] [VOTE] match expression
On Mon, Apr 27, 2020 at 3:57 PM Andrea Faulds wrote: > Hi, > > I share Dan's reasons for voting against. I don't think things should go > to a vote before the dust has settled. > > Regards, > Andrea Faulds > Similar sentiment here. I don't think the concept has been explored sufficiently. Many people in the voting thread are calling for supporting match expressions only (without support for either statement form, or support for block expressions). The RFC motivates the match construct as an improved replacement for switch, which is type-safe, exhaustive and has no fallthrough gotchas. If we limit match to returning simple expressions only, is it still a viable replacement for switch? I've looked at a sample of ~50 switches randomly picked from popular composer packages, the list can be found here: https://gist.github.com/nikic/fc225f02ea76c02e669a598cfc471b83 I've classified these according to whether the switches could be rewritten as a match if it only supports expression, but not statement form. What I was looking for here was the ability to more or less directly translate, without having to do major refactoring first. Results: 2595: no (only with block expression support) 8337: no (only with block expression support) 2115: no 7109: no (only with block expression support) 6564: no 7786: no (only by returning a pair, and only realistic with block expression support) 2609: yes 7450: no (only by returning a triple, and only with block expression support) 5338: no 567: no 3376: yes (but weird stylistically) 2850: no 2635: yes 61: no 6562: no 2354: yes 522: no 4972: yes 8179: no 6080: yes 5997: yes 6758: yes 6718: no (only with block expression support) 1451: maybe 9152: yes 4192: no 4099: no 6773: yes 2727: yes (but weird stylistically) 6779: yes 2710: no 149: yes 7501: no 1197: no (only with block expression support) 6845: yes 6610: no 1088: yes (but weird stylistically) 2806: yes 3393: no 8361: no (only by returning a pair, and only with block expression support) 4473: no 8543: no 8792: no (only with block expression support, maybe) 8776: no 1165: yes 8388: yes 8294: no 3840: yes 3587: yes 6428: (empty switch) 8324: no 1280: no 2023: yes 8084: no (maybe with block expression support) Of the switches I looked at, 31 cannot use match in single-expression form, while 21 can. Is match intended as a replacement for switch? Or is intended to replace the ternary operator? Do we want people to be able to convert switches to matches without much hassle, or is this only intended for a specific subset? I'm not quite clear on what "match" is intended to be, and I think different people in this discussion have rather different views on this. Regards, Nikita
Re: [PHP-DEV] [VOTE] match expression
Hi, I share Dan's reasons for voting against. I don't think things should go to a vote before the dust has settled. Regards, Andrea Faulds -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] [VOTE] match expression
On 26/04/2020 09:15, Marco Pivetta wrote: I'm not fine with allowing procedural code to be executed on the right-hand-side of each match. By enforcing only expressions to be on the right-hand-side, we get some nice side-effects too: > I'd be voting YES on the RFC if the blocks were gone. I concur with Marco's statements. Mark Randall marand...@php.net -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] [VOTE] match expression
Am 26.04.2020 um 10:15 schrieb Marco Pivetta: By enforcing only expressions to be on the right-hand-side, we get some nice side-effects too: * no need to discuss `continue` * no need to discuss `break` * no need to discuss `return` Overall, that would be a win-win. Makes sense to me. A point has been risen about the fact that using closures increases memory usage and stack frames: that's a compiler optimization concern, and probably also a minor one, since I'd discourage procedural code on the RHS anyway :-) Agreed. I'd be voting YES on the RFC if the blocks were gone. Same (I think). -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] [VOTE] match expression
Am 25.04.2020 um 13:03 schrieb Dan Ackroyd: I like this idea, and would like to see 'match' in PHP. At the same time, is there any need to have the vote right now? The deadline for PHP 8 feature freeze is July 27 2020. There were changes to the proposal overnight, which people have not even had a chance to read, let alone think about. To me it feels like the RFC is being rushed to a vote, with respect to the recent changes and the technical problem you describe. I share this sentiment which is why I voted "no". -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] [VOTE] match expression
Heya, Just following up here, after private convo on why I voted "NO" on this RFC. My rationale for not wanting the RFC (in its current state) is that I don't want more procedural constructs in the language. Specifically, I'm fine with: match () { => , => , => , default => , } I'm not fine with allowing procedural code to be executed on the right-hand-side of each match. It would still possible to hide procedural code in the right-hand-side of the match, but luckily without affecting the outer scope: match () { => (function () { /* insert your procedural nightmare of choice here */ })(), => (fn () => /* more procedural nightmares here */)(), default => , } By enforcing only expressions to be on the right-hand-side, we get some nice side-effects too: * no need to discuss `continue` * no need to discuss `break` * no need to discuss `return` Overall, that would be a win-win. A point has been risen about the fact that using closures increases memory usage and stack frames: that's a compiler optimization concern, and probably also a minor one, since I'd discourage procedural code on the RHS anyway :-) I'd be voting YES on the RFC if the blocks were gone. On Sat, Apr 25, 2020 at 12:40 PM Ilija Tovilo wrote: > Hi internals > > I have opened the voting on the match expression RFC. It will end on > 9th of May, 2020. > https://wiki.php.net/rfc/match_expression > > Here are the last changes: > > In the last update I mentioned allowing return values in blocks. > Unfortunately, we discovered some technical difficulties (memory > leaks) which are very hard to solve. Nikita is experimenting on a > possible solution. There was also a fair bit of backlash over the > syntax. Thus I have decided to move block expressions to a separate > RFC. Note that blocks with just statements remain part of this RFC. > > The "duplicate condition" warning mentioned by Dan was removed due to > the arguments made by Tyson. > > I have also moved the optional semicolon for the match in statement > form to a separate vote as this was another controversial part of the > proposal. > > Furthermore I have added another secondary vote for allowing to drop > (true) conditions as that was suggested multiple times: > > match { > $age >= 30 => {}, > $age >= 20 => {}, > $age >= 10 => {}, > default => {}, > } > > // Equivalent to > > match (true) { > $age >= 30 => {}, > $age >= 20 => {}, > $age >= 10 => {}, > default => {}, > } > > There is a separate poll for specifying the reason for a "no" vote. > Let me know if there are any other reasons so I can add those to the > poll. > > A personal thank you goes out to Tyson for his guidance! > > Regards, > Ilija > Marco Pivetta http://twitter.com/Ocramius http://ocramius.github.com/
Re: [PHP-DEV] [VOTE] match expression
Hi Ilija, 1. I was confused by the vote announcement email about what "block statements" meant - https://github.com/php/php-src/pull/5371#discussion_r415079802 > Thus I have decided to move block expressions to a separate RFC. This is clarified in https://wiki.php.net/rfc/match_expression#blocks > **For the time being using blocks in match expressions that use the return > value in any way results in a compilation error:** (I personally agree with that change for this RFC introducing `match`) 2. As Dan Ackroyd mentioned, https://wiki.php.net/rfc/howto mentions: > When discussion ends, and a minimum period of two weeks has passed since you > mailed internals@lists.php.net in step 4, > consider one day heads up mail on the mailing list and then you can move your > RFC to “Voting” status. Other people may read the guidelines differently from me, and I've made small mistakes with the process in the past due to not remembering everything in the howto. (and they're guidelines instead of rules) In the future, I'd recommend: i. After finalizing the changes to the RFC and before starting the vote, email out a summary of what changed on the RFC discussion thread itself (https://externals.io/message/109590 "[DISCUSSION] Match expression") ii. Consider waiting at least 24 hours before starting the vote, extending it if you made more changes to the RFC or implementation. This would give voters a clearer idea of what was being voted on, and give people time to point out issues/blockers/new questions with the new RFC/implementation (if needed). P.S. Although it's obvious voting has started, and some other RFCs kept the title "Proposed Voting Choices", https://wiki.php.net/rfc/match_expression#proposed_voting_choices could be renamed from "Proposed Voting Choices" to "Vote" Thanks, - Tyson -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] [VOTE] match expression
Hi Dan > I like this idea, and would like to see 'match' in PHP. At the same > time, is there any need to have the vote right now? The deadline for > PHP 8 feature freeze is July 27 2020. I understand you sentiment. Let me put it this way: I've announced the first version of this RFC four weeks ago and I still have absolutely no idea what the general opinion is on this RFC, let alone the details. So even if the RFC fails I'll gain some insight on how to move forward. Regards, Ilija -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] [VOTE] match expression
> Am 25.04.2020 um 12:39 schrieb Ilija Tovilo : > > Hi internals > > I have opened the voting on the match expression RFC. It will end on > 9th of May, 2020. > https://wiki.php.net/rfc/match_expression > > Here are the last changes: > > In the last update I mentioned allowing return values in blocks. > Unfortunately, we discovered some technical difficulties (memory > leaks) which are very hard to solve. Nikita is experimenting on a > possible solution. There was also a fair bit of backlash over the > syntax. Thus I have decided to move block expressions to a separate > RFC. Note that blocks with just statements remain part of this RFC. > > The "duplicate condition" warning mentioned by Dan was removed due to > the arguments made by Tyson. > > I have also moved the optional semicolon for the match in statement > form to a separate vote as this was another controversial part of the > proposal. > > Furthermore I have added another secondary vote for allowing to drop > (true) conditions as that was suggested multiple times: > > match { >$age >= 30 => {}, >$age >= 20 => {}, >$age >= 10 => {}, >default => {}, > } > > // Equivalent to > > match (true) { >$age >= 30 => {}, >$age >= 20 => {}, >$age >= 10 => {}, >default => {}, > } > > There is a separate poll for specifying the reason for a "no" vote. > Let me know if there are any other reasons so I can add those to the > poll. > > A personal thank you goes out to Tyson for his guidance! > > Regards, > Ilija Hey Ilija, while in general I'm okay-ish with match using a strict comparison, shall the "match { $cond1 => {}, $cond2 => {} }" syntax be strict or not? I would do a simple truthiness check in that particular case (which IMHO is also consistent as there is no explicit value it's compared against). That way it would essentially have the semantics of a chained ternary without being illegible. At least as match {} without explicit expected value is effectively a boolean comparison (doesn't feel really like a strict value comparison), it should also behave like a classical boolean comparison. In general, apart from that very last change (I think you should have given it at least 1-2 days of consideration before starting the vote), the RFC is nice and provides a concise syntax for something which usually is quite uglily expressed. Bob -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] [VOTE] match expression
On Sat, 25 Apr 2020 at 11:40, Ilija Tovilo wrote: > > Hi internals > > I have opened the voting on the match expression RFC. It will end on > 9th of May, 2020. > https://wiki.php.net/rfc/match_expression > > Here are the last changes: Hi Ilija, I like this idea, and would like to see 'match' in PHP. At the same time, is there any need to have the vote right now? The deadline for PHP 8 feature freeze is July 27 2020. There were changes to the proposal overnight, which people have not even had a chance to read, let alone think about. To me it feels like the RFC is being rushed to a vote, with respect to the recent changes and the technical problem you describe. > Unfortunately, we discovered some technical difficulties (memory > leaks) which are very hard to solve. Nikita is experimenting on a > possible solution. It also seems the voting options were also changed last night. - The vote is a straight Yes/No vote for accepting the RFC and merging the patch. + "Would you like to add match expressions to the language?" + "Should the semicolon for match in statement form be optional?" + "Should we allow dropping (true) condition?" I think it would be better to continue the conversation and work through the trade-offs when voting isn't active, rather than just hoping people pick the correct choices, or have a contentious time-limited discussion. cheers Dan Ack -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php