Re: [PHP-DEV] [VOTE] match expression

2020-04-30 Thread Rowan Tommins
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

2020-04-30 Thread Ilija Tovilo
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

2020-04-30 Thread Илья Сомов
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

2020-04-30 Thread Илья Сомов
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

2020-04-29 Thread Rowan Tommins

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

2020-04-29 Thread Larry Garfield
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

2020-04-28 Thread Ilija Tovilo
> 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

2020-04-28 Thread Levi Morrison via internals
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

2020-04-28 Thread Larry Garfield
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

2020-04-28 Thread Levi Morrison via internals
> 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

2020-04-28 Thread Larry Garfield
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

2020-04-28 Thread Rowan Tommins
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

2020-04-28 Thread Bob Weinand



> 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

2020-04-28 Thread 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]


Re: [PHP-DEV] [VOTE] match expression

2020-04-28 Thread Ilija Tovilo
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

2020-04-28 Thread Rowan Tommins
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

2020-04-28 Thread Nikita Popov
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

2020-04-27 Thread Andrea Faulds

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

2020-04-26 Thread Mark Randall

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

2020-04-26 Thread Sebastian Bergmann

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

2020-04-26 Thread Sebastian Bergmann

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

2020-04-26 Thread Marco Pivetta
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

2020-04-25 Thread tyson andre
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

2020-04-25 Thread Ilija Tovilo
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

2020-04-25 Thread Bob Weinand
> 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

2020-04-25 Thread Dan Ackroyd
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