Re: [PHP-DEV] Re: [VOTE] Userspace operator overloading
On Wed, Mar 25, 2020 at 6:28 AM Christoph M. Becker wrote: > > It seems to me that the RFC is not sufficiently specific enough > regarding the concatenation of instances of classes which implement > __toString(). Exactly what I was thinking too. Would be nice with some examples on this. > So if we ever wanted to change the value of > PHP_OPERAND_TYPES_NOT_SUPPORTED, we'd introduce a BC break. Therefore > the constant's value likely will never change, so using NULL directly to > signal unsupported operand types would be fine, wouldn't it? Agree on this too. -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] Improving PHP's Object Egonomics: A broad analysis
Hi Larry and Nicolas, On Wed, Mar 25, 2020 at 9:24 AM Larry Garfield wrote: > > I'd like to propose something on the topic. > > I'm adding object literals to the mix because that's another feature of the > > language that we're missing a lot IMHO. > > Actually, there is one existing syntax for objects: (object) [...] > > [...] > > 2) What's its order of execution with the constructor? Vis, does the > constructor run after __create or before? Does __construct get any > parameters passed to it? That's the interesting question, though there's probably not any sensible answer that works for all use cases. However, if this kind of object casting (object literal notation) was limited to a certain (extendable) internal class (SPL Struct?), we could have just a final public function __construct(array $properties = []) that then delegates the validation to an abstract __validation() method. Would that at least be a useful alternative to constructor promotion? > In that syntax, you have to remember which one comes first. There's no > indication for the casual reader why > > public private $property; > > and > > private public $property; I'm wondering - are there any use cases where you would have private read and public write? If not, maybe this issue can be simplified by adding (f.ex.) "semiprivate" and "semiprotected" attribute keywords, the idea being that they give readonly access to the anything else. Though I think it would be great to have a nice, gracefully extensible attribute syntax, maybe it's not necessary to fight over that for this particular issue? > Either way, what matters is who is in charge of dealing with the issues > this might create. In both ways, what matters is that the original author > won't be bothered for things that are not its responsibility. "I broke your > app because you messed up with that private property on a class I > authored?" no my problem. About final, I usually prefer using the "@final" > annotation: it expressed exactly what I need to express as the author of > the code: "if you extend, you're on your own - but I'm not dictating what > you can/can't do either". > > I think this reasoning applies to my view on immutability :) :-) I can relate to that in general. Though for immutability, I'm not so sure anymore... -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
[PHP-DEV] RFC Raised for str_starts_with and str_ends_with
Hi, Hope everyone is doing alright. I just raised a new RFC (https://wiki.php.net/rfc/add_str_starts_with_and_ends_with_functions , github patch: https://github.com/php/php-src/pull/5300) for adding str_starts_with and str_ends_with to PHP. I would like to open this RFC up to discussion. I raised a similar RFC about 9 months ago (https://wiki.php.net/rfc/add_str_begin_and_end_functions) that was narrowly rejected. A major criticism of that RFC was the inclusion of case-insensitive versions of str_starts_with and str_ends_with. I have incorporated feedback from that experienced and narrowed the new RFC to only propose str_starts_with and str_ends_with. Thanks, Will -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] Removing warning for failed include
> Le 26 mars 2020 à 01:11, Levi Morrison via internals > a écrit : > > It's bothered me for quite some time that a failed include emits a > warning. This is because it's by design that the author chose > `include` and not `require`. It's _expected_ that it may fail and they > are okay with that. > > As an example, consider a classic autoloading case. It could be as > simple and performant as: > >$file = /* something derived from class name */; >include $file; > > But because of the warning, in practice authors tend to use > `file_exists` + require instead: > >$file = /* something derived from class name */; >if (file_exists($file)) { >require $file; >} > > Weird isn't it? Authors are using require instead of include for the > case where failure is tolerated. This is a clear signal to me that > include isn't doing its job. The warning gets in the way. > > Any reasons we shouldn't just remove this warning for PHP 8? > A quick look on the code base I’m taking care of, reveals that most `include` instructions expect that the file will be in fact included. If it isn’t, the error handler will be triggered and send me a bug report. (Yes I know, all those `include` could have been spelled `require`.) On the other hand, in the occasional cases where I do want to include a file only if it exists, I wouldn’t lightheartedly remove the `file_exists()` check, because its presence makes the intent of the code clearer. —Claude -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] Class cast
Hello! > What's wrong with new Number(123)? Actually it is a simplest case, where only a single information was considered. But you can expand it to something more complex, where currently you will need create a static method to copy the data, which is not a normalized way like cast could do. > Not sure why would you want to do this? What's the use case? You could mix the previous answer when arguments to a method that expects a Number, for instance: X::test((Number) $x). Or you can increase the type of information when possible. For instance: function requiresB(B $b); But you have only A $a. You can create: function __cast($value) { if ($value instanceof A) return B($value, 123, M_PI); } Then use: requiresB((B) $a); Atenciosamente, David Rodrigues Em qua., 25 de mar. de 2020 às 20:06, Stanislav Malyshev < smalys...@gmail.com> escreveu: > Hi! > > > 1. Converting from A to B: > > > > $a = 123; > > $b = (Number) $a; // $b is now instanceof Number > > > > A instanceof Number will created based on $a value. > > What's wrong with new Number(123)? > > > 2. Reduce object type (I don't know the technical term): > > > > class A {} > > class B extends A {} > > > > $b = new B; > > $a = (A) $b; > > > > $a still is $b, but with "limited" access to A methods and properties. > > Not sure why would you want to do this? What's the use case? > -- > Stas Malyshev > smalys...@gmail.com >
[PHP-DEV] Removing warning for failed include
It's bothered me for quite some time that a failed include emits a warning. This is because it's by design that the author chose `include` and not `require`. It's _expected_ that it may fail and they are okay with that. As an example, consider a classic autoloading case. It could be as simple and performant as: $file = /* something derived from class name */; include $file; But because of the warning, in practice authors tend to use `file_exists` + require instead: $file = /* something derived from class name */; if (file_exists($file)) { require $file; } Weird isn't it? Authors are using require instead of include for the case where failure is tolerated. This is a clear signal to me that include isn't doing its job. The warning gets in the way. Any reasons we shouldn't just remove this warning for PHP 8? -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] Class cast
Hi! > 1. Converting from A to B: > > $a = 123; > $b = (Number) $a; // $b is now instanceof Number > > A instanceof Number will created based on $a value. What's wrong with new Number(123)? > 2. Reduce object type (I don't know the technical term): > > class A {} > class B extends A {} > > $b = new B; > $a = (A) $b; > > $a still is $b, but with "limited" access to A methods and properties. Not sure why would you want to do this? What's the use case? -- Stas Malyshev smalys...@gmail.com -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] [RFC] [DISCUSSION] Type casting in array destructuring expressions
To me, this is almost a good idea. However, I would want regular type checking, not casts. Importantly, regular type checks would fit well on allowing array destructuring directly in function signatures, which would basically be a form of named parameters. -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] Re: [RFC][DISCUSSION] throw expression
Ilija Tovilo wrote: Hi Andrea but I am surprised you haven't mentioned the `and` and `or` operators I did mention them in the RFC here: https://wiki.php.net/rfc/throw_expression If this RFC is accepted they will indeed be possible __ Regards Oh, you are quite right! Sorry, I must not have read it too carefully :( -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] [RFC][DISCUSSION] throw expression
Hi Andrea > I would think we can just give `throw` an appropriate precedence so that > expressions like the above do what is desired The example are taken from the RFC online. The following expression is already possible: ```php throw $condition1 && $condition2 ? new Exception1() : new Exception2(); ``` To make sure it keeps working the precedence needs to me very low. Thus the precedence might be slightly surprising which is why Dan suggests printing a warning. Regards -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] Re: [RFC][DISCUSSION] throw expression
Hi Andrea > but I am surprised you haven't mentioned the `and` and `or` operators I did mention them in the RFC here: https://wiki.php.net/rfc/throw_expression If this RFC is accepted they will indeed be possible __ Regards -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] [RFC][DISCUSSION] throw expression
Hi Dan, Dan Ackroyd wrote: Regarding the example: $condition || throw new Exception('$condition must be truthy') && $condition2 || throw new Exception('$condition2 must be truthy'); The "Deprecate left-associative ternary operator"* RFC made it so that parentheses are required when ternary operators are nested in complicated statements. Would a similar requirement for parentheses around complicated throw expressions be a suitable solution to avoid people being surprised by the behaviour? cheers Dan Ack * https://wiki.php.net/rfc/ternary_associativity Is there a strong reason to require parentheses? I would think we can just give `throw` an appropriate precedence so that expressions like the above do what is desired — and then if you wanted to do something unusual, you would have to add parentheses anyway. Regards, Andrea -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
[PHP-DEV] Re: [RFC][DISCUSSION] throw expression
Hey Ilija, Ilija Tovilo wrote: Hi everybody! I hope you’re doing well. Due to the modest feedback I’d like to move the throw expression RFC to “under discussion”. https://wiki.php.net/rfc/throw_expression In short, the RFC proposes to convert the throw statement into an expression to make it usable in arrow functions, the coalesce operator, as well as the ternary/elvis operator. Thanks for this RFC, I have wanted this sometimes when writing PHP code. The ?? operator is one of those places, but I am surprised you haven't mentioned the `and` and `or` operators. It is classic PHP style (probably borrowed from Perl?) to write e.g.: $mysql = mysql_open(...) or die("Couldn't connect to MySQL"); Obviously not very modern with use of mysql_ ;) But the `or` operator is still quite handy for this kind of trivial error handling, and it would be great to be able to write e.g.: $fp = @fopen($filename, "r") or throw new Exception("Couldn't open file!"); Likewise for `and` (I think it is less common): $somethingWentWrong and throw new Exception("Oh no!"); So I would be happy to see `throw` become an expression for these reasons, even if it is a bit conceptually weird given it never returns anything! Thanks, Andrea -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] [RFC] [DISCUSSION] Type casting in array destructuring expressions
Hi, Enno, En mié, 25 mar 2020 18:53:15 +0100 Enno Woortmann escribió > Hi, > > I've written the RFC and implemented a first patch concerning the idea > to allow type casting in array destructuring expressions. > > > The RFC is located at https://wiki.php.net/rfc/typecast_array_desctructuring > > The patch can be found in MR 5296 located at > https://github.com/php/php-src/pull/5296 > > > Thanks for further feedback! > > Cheers, Enno > I like your RFC. I hope it is approved. However, I would change your examples. Because, this one: ["now" => (int) $now, "future" => (int) $future] = ["now" => "2020", "name" => "2021"]; You could do casting in this way: ["now" => $now, "future" => $future] = array_map('intval', ["now" => "2020", "name" => "2021"] ); If I were you I add examples with mixed types, like: ["address" => (string) $address, "floor" => (int) $floor] = ["address" => "My adress", "floor" => "3"]; I'm sorry my English Regards -- Manuel Canga -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] [RFC] switch expression
Hi, internals, En mié, 25 mar 2020 17:21:29 +0100 Rowan Tommins escribió > On Wed, 25 Mar 2020 at 15:29, Ilija Tovilo wrote: > > > I don't think this would add any significant benefit over: > > > > ```php > > $x = true switch { > > $x !== null && $x < 5 => ... > > } > > ``` > > > > > The problem with that is that it requires a temporary variable to be > switched on. If I want to switch on, say, a method call, I can write this > for equality: > > $result = $this->foo($bar) switch { > 1 => 'hello', > 2 => 'hi', > 3 => 'goodbye' > }; In this case, you can also do: $result = [ 1 => 'hello', 2 => 'hi', 3 => 'goodbye' ][$this->foo($bar)]; With syntax very similar to proposed switch but this is using array. Regards -- Manuel Canga -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
[PHP-DEV] [RFC] [DISCUSSION] Type casting in array destructuring expressions
Hi, I've written the RFC and implemented a first patch concerning the idea to allow type casting in array destructuring expressions. The RFC is located at https://wiki.php.net/rfc/typecast_array_desctructuring The patch can be found in MR 5296 located at https://github.com/php/php-src/pull/5296 Thanks for further feedback! Cheers, Enno -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] Class cast
> > Currently PHP supports generic castings like (string), (int), ... maybe is > time to allow class castings like (ToClass) $fromObject? I've proposed something similar a year ago: https://externals.io/message/105332 My intention wasn't to create an object from a scalar, nor was it to limit to a class' methods & properties (hardly possible in PHP), but to ensure that the value is an instance of the given class/interface, or throw an exception. My proposal wasn't so well received, though. — Ben
Re: [PHP-DEV] [RFC] switch expression
On 25.03.2020 at 17:06, Dennis Birkholz wrote: > Hello together, > > Am 25.03.20 um 16:46 schrieb Larry Garfield: >> On Wed, Mar 25, 2020, at 10:29 AM, Ilija Tovilo wrote: >>> Thanks for your feedback, Larry! >>> One possible improvement to either version is allowing an expression on the left side. That is, rather than doing an equality match, do a boolean match. >>> >>> This is how Rust does it: >>> >>> ```rust >>> let x = match ... { >>> Some(y) if y < 5 => ... >>> } >>> ``` >>> >>> In other words, you can add an additional guard to each case that >>> excepts any expression. We don't really benefit a lot from that since >>> we don't have pattern matching. I don't think this would add any >>> significant benefit over: >>> >>> ```php >>> $x = true switch { >>> $x !== null && $x < 5 => ... >>> } >>> ``` >> >> Good point, I'd forgotten about that potential trick. So as long as an >> expression is allowed on the left, rather than just a literal, which is then >> == compared against the provided value, that should be "good enough" for >> most use cases. >> >> The implementation should include some tests to make sure that works >> properly, but I'm happy with the resulting syntax. >> >> So then the net result is: >> >> $var = switch($val) { >> case expr1 => expr2; >> } >> >> Where $val gets compared against the result of each expr1, and if true then >> $var is set to expr2. > > on the first glance this all looks nice but you actually created > something more like an if-expression that uses switch as a keyword > because you stripped switch of some of its major features: > - you compare the given value to possible cases -> you compare > expressions to true > - you can fall through to other cases without break > - what about the default case? > > What about the following if-expression-syntax: > > $var = if ($x > 0) { return 1; } >elseif ($x < 0) { return -1; } >else { return 0; } > > Maybe this is more in line of what you want to do with your switch > expression? Or maybe even $var = $x > 0 ? 1 :($x < 0 ? -1 : 0); Yes, the required parentheses are ugly, but in my opinion, this is still better than a new if or switch(true) expression construct. -- Christoph M. Becker -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
[PHP-DEV] Class cast
Currently PHP supports generic castings like (string), (int), ... maybe is time to allow class castings like (ToClass) $fromObject? I think that it could be useful to converts to another kind of structure, or even to reduce object type. For instance: --- 1. Converting from A to B: $a = 123; $b = (Number) $a; // $b is now instanceof Number A instanceof Number will created based on $a value. --- 2. Reduce object type (I don't know the technical term): class A {} class B extends A {} $b = new B; $a = (A) $b; $a still is $b, but with "limited" access to A methods and properties. --- To make possible custom some kind of castings, I suggests a new magic method __cast($value). class Number { ... function __cast($value) { if (is_int($value) || is_float($value)) return new static($value); throw new TypeError(); } } Just to talk. Atenciosamente, David Rodrigues
Re: [PHP-DEV] [RFC] switch expression
Hi Rowan > The problem with that is that it requires a temporary variable to be > switched on. If I want to switch on, say, a method call, I can write this > for equality: I agree. The iffy part would be recognizing if the case expression should be equated to the switch input or evaluated on its own. That is still something we could address in a later RFC for both the statement and expression. Regards -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] [RFC] switch expression
Hi Dennis Thanks for your feedback! > you can fall through to other cases without break You could do the same using the || operator. > what about the default case? I haven't described the default case in my proposal but it is exactly what you'd expect it to be: ```php $var = true switch { $x > 0 => 1, $x < 0 => -1, default => 0, }; ``` > What about the following if-expression-syntax: That would work (once again, Rust already does it) though not with the return keyword. We'd still need a block expression to pass the value from the block to the if expression. When I compare the two I definitely think the match expression is more readable. Regards -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] [RFC] switch expression
On Wed, 25 Mar 2020 at 15:29, Ilija Tovilo wrote: > I don't think this would add any significant benefit over: > > ```php > $x = true switch { > $x !== null && $x < 5 => ... > } > ``` > The problem with that is that it requires a temporary variable to be switched on. If I want to switch on, say, a method call, I can write this for equality: $result = $this->foo($bar) switch { 1 => 'hello', 2 => 'hi', 3 => 'goodbye' }; For inequalities, the switch(true) version looks something like this (the parentheses would probably be optional, but I'd personally use them for readability): $temp = $this->foo($bar); $result = true switch { ($temp <= 1) => 'hello', ($temp == 2) => 'hi', default => 'goodbye' } Using $$ to mean "value tested" would mean you could get rid of the temp variable, and just write this: $result = $this->foo($bar) switch { ($$ <= 1) => 'hello', ($$ == 2) => 'hi', default => 'goodbye' }; I've also previously thought about specifying an operator for switch statements, which could be used with expressions as well, e.g. $result = $this->foo($bar) switch <= { 1 => 'hello', 2 => 'hi', default => 'goodbye' }; Again, though, this is something that could be added to switch statements and expressions together, as a separate RFC. Regards, -- Rowan Tommins [IMSoP]
Re: [PHP-DEV] Improving PHP's Object Egonomics: A broad analysis
Am 25.03.20 um 15:24 schrieb Larry Garfield: > On Wed, Mar 25, 2020, at 5:57 AM, Nicolas Grekas wrote: >> Máté suggested this syntax and it has my preference over the one you menton >> Larry: doubling the visibility keyword could be enough to express >> read+write access: >> >> public private $property; <= public read access, private write access > > In that syntax, you have to remember which one comes first. There's no > indication for the casual reader why > > public private $property; > > and > > private public $property; > > are different. Plus, just looking at it, "wait, it's public and private? > WTF? That doesn't even make sense." > > It also doesn't extend gracefully to property accessors. Whatever accessors > do, if they ever get resolved, would conflict with that, and thus we'd have > that many more weird combinations of property metadata that are incompatible. > > The whole point of the syntax I proposed for asymmetric visibility is that > it's gracefully extensible, even if a little more verbose. (If we can find a > syntax that is less verbose while still gracefully extensible, I am on board > with that.) What about the following syntax: class X { public read private write $property; } That would play nicely with accessors: class Y { public read getProp private write setProp Type $property; // or this way around to make it clear which is the setter // and which is the property type public getProp read private setProp write Type $property; private function getProp() : ?Type {} private function setProp (Type $newValue) {} } It seems to me this would allow a clear syntax where you can selectively add accessor method for reading or writing or both, you can reuse existing setting methods when refactoring. Only the isset/unset accessors are missing. I am not sure if they are necessary: isset could be equivalent to ($obj->getProp() !== null) and unset to setting null, but I have not thought this through yet. Greets Dennis -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] [RFC] switch expression
Hello together, Am 25.03.20 um 16:46 schrieb Larry Garfield: > On Wed, Mar 25, 2020, at 10:29 AM, Ilija Tovilo wrote: >> Thanks for your feedback, Larry! >> >>> One possible improvement to either version is allowing an expression on the >>> left side. That is, rather than doing an equality match, do a boolean >>> match. >> >> This is how Rust does it: >> >> ```rust >> let x = match ... { >> Some(y) if y < 5 => ... >> } >> ``` >> >> In other words, you can add an additional guard to each case that >> excepts any expression. We don't really benefit a lot from that since >> we don't have pattern matching. I don't think this would add any >> significant benefit over: >> >> ```php >> $x = true switch { >> $x !== null && $x < 5 => ... >> } >> ``` > > Good point, I'd forgotten about that potential trick. So as long as an > expression is allowed on the left, rather than just a literal, which is then > == compared against the provided value, that should be "good enough" for most > use cases. > > The implementation should include some tests to make sure that works > properly, but I'm happy with the resulting syntax. > > So then the net result is: > > $var = switch($val) { > case expr1 => expr2; > } > > Where $val gets compared against the result of each expr1, and if true then > $var is set to expr2. on the first glance this all looks nice but you actually created something more like an if-expression that uses switch as a keyword because you stripped switch of some of its major features: - you compare the given value to possible cases -> you compare expressions to true - you can fall through to other cases without break - what about the default case? What about the following if-expression-syntax: $var = if ($x > 0) { return 1; } elseif ($x < 0) { return -1; } else { return 0; } Maybe this is more in line of what you want to do with your switch expression? Greets Dennis -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] [RFC] switch expression
On Wed, Mar 25, 2020, at 10:29 AM, Ilija Tovilo wrote: > Thanks for your feedback, Larry! > > > One possible improvement to either version is allowing an expression on the > > left side. That is, rather than doing an equality match, do a boolean > > match. > > This is how Rust does it: > > ```rust > let x = match ... { > Some(y) if y < 5 => ... > } > ``` > > In other words, you can add an additional guard to each case that > excepts any expression. We don't really benefit a lot from that since > we don't have pattern matching. I don't think this would add any > significant benefit over: > > ```php > $x = true switch { > $x !== null && $x < 5 => ... > } > ``` Good point, I'd forgotten about that potential trick. So as long as an expression is allowed on the left, rather than just a literal, which is then == compared against the provided value, that should be "good enough" for most use cases. The implementation should include some tests to make sure that works properly, but I'm happy with the resulting syntax. So then the net result is: $var = switch($val) { case expr1 => expr2; } Where $val gets compared against the result of each expr1, and if true then $var is set to expr2. Endorse. --Larry Garfield -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] [RFC] switch expression
Thanks for your feedback, Larry! > One possible improvement to either version is allowing an expression on the > left side. That is, rather than doing an equality match, do a boolean match. This is how Rust does it: ```rust let x = match ... { Some(y) if y < 5 => ... } ``` In other words, you can add an additional guard to each case that excepts any expression. We don't really benefit a lot from that since we don't have pattern matching. I don't think this would add any significant benefit over: ```php $x = true switch { $x !== null && $x < 5 => ... } ``` Regards -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] [RFC] switch expression
On Wed, Mar 25, 2020, at 9:27 AM, Ilija Tovilo wrote: > Hi Michał > > > > I’m sorry, unfortunately I missed your e-mail and RFC. > > Let me know if you’re still working on it and I’ll back off of course. > > > > Regards I like the concept, and it looks like you're both on a similar track. Give or take details, I would very much like to see something like it. One possible improvement to either version is allowing an expression on the left side. That is, rather than doing an equality match, do a boolean match. That would then allow: $foo = switch($bar) { case $bar < 5 => $bar * 3; case $baz < 10 => $bar * 4; default => $bar * 5; }; That would sidestep the need for pattern matching, as you can do anything an expression can do. The obvious caveat of course is figuring out how to reference the variable being switched on, if it's not already a variable. My first thought there is to borrow the $$ variable name from Sara's old function composition proposal, but there may be others. There's likely other issues to discuss here but allowing expressions on the left would greatly improve the expressiveness of the construct. I'd prefer to not allow multi-line statements on the right, ie, blocks. That leads to too much potential for long and ugly code, which a construct like this should be avoiding. Limiting it to a single expression keeps it compact; if you have more involved logic, then put it in a function and your expression is just... calling that function. Problem solved. Side note: I did a limited user-space implementation of the same concept a while back: https://hive.blog/php/@crell/type-matching-in-php But I'd definitely rather see it in the native syntax. --Larry Garfield -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] [RFC] switch expression
Hi Michał I’m sorry, unfortunately I missed your e-mail and RFC. Let me know if you’re still working on it and I’ll back off of course. Regards
Re: [PHP-DEV] Improving PHP's Object Egonomics: A broad analysis
On Wed, Mar 25, 2020, at 5:57 AM, Nicolas Grekas wrote: > > > https://hive.blog/php/@crell/improving-php-s-object-ergonomics > > Named parameters are a pretty tough topic. I think one of the main points > > of contention is that they make the parameters names part of the API > > contract, and as such also subject to LSP. Your proposal offers two > > possible ways to side-step this: First, by making named parameters opt-in > > with a special syntax {}. Second, by limiting them to constructors. The > > latter variant still exposes parameter names in the API, but at least does > > not require their preservation across inheritance, as constructors are > > excluded from LSP. I'm somewhat torn on this, because it makes named > > parameters unusable with the very large body of existing methods, and > > introduces an inconsistency in which methods can use named params and which > > don't. > > > > I'd like to propose something on the topic. > I'm adding object literals to the mix because that's another feature of the > language that we're missing a lot IMHO. > Actually, there is one existing syntax for objects: (object) [...] > > My proposal is to allow any class in the casting operator: (Foo) [...] > By default, all keys of the casted array would map to properties (with an > error when no matching property exists in the current visibility scope). We > would then allow for a new constructor method, either: > public function __create(array $values) > or: > public static function __create(array $values): static > > This method would take over the cast operator and decide how to construct > an instance of such a class. > > There is one drawback: accepted keys are not documented. Sure, property > declarations can give a big hint. > > But I think we can solve this issue later: it's not a blocker to still make > things work nicely. Also, this issue already exists with all methods that > accept an array of options - and we'll find a solution for those - either > using docblocks (there are already ways to use them for that) or using > attributes (would be the best of course, once we have them.) > > Note that this __create() method looks a lot like __unserialize(): it's > just called at a different place, but the implementations could be > essentially the same. Interesting. If that allowed populating private properties than that would be more capable than either of the initializer proposals that have been put forward. However, this alternate deserialization (as you note, it's basically __unserialize by another name) brings up other issues: 1) If it's a large number of properties, the __create method would still need to manually assign them to properties, just like constructors now. It wouldn't benefit from constructor promotion. 2) What's its order of execution with the constructor? Vis, does the constructor run after __create or before? Does __construct get any parameters passed to it? If it doesn't get called, that's yet another way to bypass the constructor and therefore bypass object validation. ("Make invalid states unrepresentable". If the properties don't logically make sense with each other that should be rejected as early as possible; syntactically if we can, via early validation if not.) Named parameters have neither of those issues, as data still only comes in via the constructor so both promotion and validation work fine. > Regarding the remainder, I think that all of readonly properties, > > asymmetric visibility and property accessors have their place and value, > > with some overlap between them. As you already mentioned, the previous > > property accessors proposal also included asymettric visibility as a > > special case, and that's how I would introduce it as well. > > > > Máté suggested this syntax and it has my preference over the one you menton > Larry: doubling the visibility keyword could be enough to express > read+write access: > > public private $property; <= public read access, private write access In that syntax, you have to remember which one comes first. There's no indication for the casual reader why public private $property; and private public $property; are different. Plus, just looking at it, "wait, it's public and private? WTF? That doesn't even make sense." It also doesn't extend gracefully to property accessors. Whatever accessors do, if they ever get resolved, would conflict with that, and thus we'd have that many more weird combinations of property metadata that are incompatible. The whole point of the syntax I proposed for asymmetric visibility is that it's gracefully extensible, even if a little more verbose. (If we can find a syntax that is less verbose while still gracefully extensible, I am on board with that.) --Larry Garfield -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] [RFC] switch expression
Hi Ilija, śr., 25 mar 2020 o 13:10 Ilija Tovilo napisał(a): > Hi everybody! > > > > A few years ago I suggested adding a new `match` expression to the PHP > language: > > https://externals.io/message/100487 > > > > I arrogantly assumed someone will implement it for me which of course > didn't happen. I'd finally like to get my own hands dirty. I have a very > rough, incomplete prototype but I'd like to get your feedback before I > continue working on the details. > > > > # Introduction > > > > This is what it looks like: > > > > ```php > > echo $i switch { > > 0 => "i equals 0", > > 1 => "i equals 1", > > 2 => "i equals 2", > > 3, 4 => "i equals 3 or 4", > > }; > > > > // is roughly equivalent to > > > > switch ($i) { > > case 0: > > $tmp = "i equals 0"; > > break; > > case 1: > > $tmp = "i equals 1"; > > break; > > case 2: > > $tmp = "i equals 2"; > > break; > > case 3: > > case 4: > > $tmp = "i equals 3 or 4"; > > break; > > default: > > throw new InvalidArgumentException('Unhandled switch case'); > > } > > > > echo $tmp; > > ``` > > > > Some things to note: > > > > * Each case only accepts a single expression > > * The entire switch expression evaluates to the result of the executed case > > * There is no fallthrough, an implicit break is added after every case > > * Multiple case conditions are possible with comma separation > > * The default case throws a InvalidArgumentException by default > > * The switch keyword is used as an infix operator > > > > # Syntax > > > > Originally, I expected to reuse the current syntax and transform it into > an expression. > > > > ```php > > $x = switch ($y) { ... }; > > ``` > > > > Turns out this is ambiguous. > > > > ```php > > switch ($y) { ... } > > [$a] = ...; > > > > // Could also be interpreted as > > switch ($y) { ... }[$a] = ...; > > ``` > > > > I stole the new syntax from C# 8.0 which means at least some people will > already be familiar with it: > > > https://docs.microsoft.com/en-us/archive/msdn-magazine/2019/may/csharp-8-0-pattern-matching-in-csharp-8-0#the-evolution-of-pattern-matching-in-c-80 > > > > # Type coercion > > > > One of the bigger weak points of the `switch` statement is the fact that > it performs implicit type coercion. > > > > ```php > > switch ('foo') { > > case 0: > > echo "Oh no!\n"; > > } > > ``` > > > > While it's very tempting to fix this in the new `switch` expression it > adds a confusing discrepancy between the `switch` statement and expression. > I think it would be preferrable to keep the two the same and change the > behavior of both in a new PHP edition ( > https://github.com/php/php-rfcs/pull/2). > > > > # Pattern matching > > > > I decided against pattern matching because PHP doesn't have algebraic data > types and classes rarely have public properties. In my opinion the limited > use cases don't justify the significant complexity added to the language. > It would also, once again, add an unjustified discrepancy between the > `switch` statement and expression. If at some point we do want to introduce > pattern matching it might be better to introduce a different keyword (e.g. > `match`) and make it work for both the statement and expression. In case > you need to match a more complex expression the following still works fine: > > > > ```php > > echo true switch { > > is_int($x) => 'int', > > is_float($x) => 'float', > > is_string($x) => 'string', > > ... > > }; > > ``` > > > > # Blocks > > > > Sometimes it would be useful to split the expression into multiple > statements to make it more readable. Unfortunately, in PHP there are no > block expressions. Rust allows returning the last value by omitting the > semicolon: > > > > ```php > > echo $x switch { > > 1 => { > > foo(); > > bar(); > > baz() > > }, > > }; > > ``` > > > > This is indeed possible in PHP and could be implemented as part of the > `switch` expression or as a general language feature. A nice side effect is > that this could also be used in arrow functions: > > > > ```php > > $x = fn() => { > > foo(); > > bar(); > > baz() > > }; > > ``` > > > > This would, however, make it inconsistent with closures as they use the > return keyword. Thus we would probably have to make sure arrow functions > still work with return statement which would decrease the need for such a > language construct. It is also very unlike anything else in PHP. > > > > # Poll > > > > This is a short overview of what I'll be working on in the coming weeks. I > created a short poll for you guys to let me know if this idea is worth > pursuing: > > https://forms.gle/stXMv72CAaDDxfwf8 > > > > Stay safe! > > That looks like what I've described a few months ago in https://wiki.php.net/rfc/switch-expression-and-statement-improvement If you dig into the mailing list you can even find almost ready to use
[PHP-DEV] [RFC] switch expression
Hi everybody! A few years ago I suggested adding a new `match` expression to the PHP language: https://externals.io/message/100487 I arrogantly assumed someone will implement it for me which of course didn't happen. I'd finally like to get my own hands dirty. I have a very rough, incomplete prototype but I'd like to get your feedback before I continue working on the details. # Introduction This is what it looks like: ```php echo $i switch { 0 => "i equals 0", 1 => "i equals 1", 2 => "i equals 2", 3, 4 => "i equals 3 or 4", }; // is roughly equivalent to switch ($i) { case 0: $tmp = "i equals 0"; break; case 1: $tmp = "i equals 1"; break; case 2: $tmp = "i equals 2"; break; case 3: case 4: $tmp = "i equals 3 or 4"; break; default: throw new InvalidArgumentException('Unhandled switch case'); } echo $tmp; ``` Some things to note: * Each case only accepts a single expression * The entire switch expression evaluates to the result of the executed case * There is no fallthrough, an implicit break is added after every case * Multiple case conditions are possible with comma separation * The default case throws a InvalidArgumentException by default * The switch keyword is used as an infix operator # Syntax Originally, I expected to reuse the current syntax and transform it into an expression. ```php $x = switch ($y) { ... }; ``` Turns out this is ambiguous. ```php switch ($y) { ... } [$a] = ...; // Could also be interpreted as switch ($y) { ... }[$a] = ...; ``` I stole the new syntax from C# 8.0 which means at least some people will already be familiar with it: https://docs.microsoft.com/en-us/archive/msdn-magazine/2019/may/csharp-8-0-pattern-matching-in-csharp-8-0#the-evolution-of-pattern-matching-in-c-80 # Type coercion One of the bigger weak points of the `switch` statement is the fact that it performs implicit type coercion. ```php switch ('foo') { case 0: echo "Oh no!\n"; } ``` While it's very tempting to fix this in the new `switch` expression it adds a confusing discrepancy between the `switch` statement and expression. I think it would be preferrable to keep the two the same and change the behavior of both in a new PHP edition (https://github.com/php/php-rfcs/pull/2). # Pattern matching I decided against pattern matching because PHP doesn't have algebraic data types and classes rarely have public properties. In my opinion the limited use cases don't justify the significant complexity added to the language. It would also, once again, add an unjustified discrepancy between the `switch` statement and expression. If at some point we do want to introduce pattern matching it might be better to introduce a different keyword (e.g. `match`) and make it work for both the statement and expression. In case you need to match a more complex expression the following still works fine: ```php echo true switch { is_int($x) => 'int', is_float($x) => 'float', is_string($x) => 'string', ... }; ``` # Blocks Sometimes it would be useful to split the expression into multiple statements to make it more readable. Unfortunately, in PHP there are no block expressions. Rust allows returning the last value by omitting the semicolon: ```php echo $x switch { 1 => { foo(); bar(); baz() }, }; ``` This is indeed possible in PHP and could be implemented as part of the `switch` expression or as a general language feature. A nice side effect is that this could also be used in arrow functions: ```php $x = fn() => { foo(); bar(); baz() }; ``` This would, however, make it inconsistent with closures as they use the return keyword. Thus we would probably have to make sure arrow functions still work with return statement which would decrease the need for such a language construct. It is also very unlike anything else in PHP. # Poll This is a short overview of what I'll be working on in the coming weeks. I created a short poll for you guys to let me know if this idea is worth pursuing: https://forms.gle/stXMv72CAaDDxfwf8 Stay safe!
Re: [PHP-DEV] [VOTE] Userspace operator overloading
Hi, internals! I want to mention, that all existing internal API of Zend could be accessible via FFI as of PHP7.4. This gives opportunity to implement userspace operator overloading as a simple PHP package. I know, that FFI requires some polishing, but it could become a tool to create interesting extensions via Z-Engine or similar libraries. Just for example, I have a repository https://github.com/lisachenko/native-types which provides an example of userspace operator-overloading for matrices (see __doOperation method implementation at https://github.com/lisachenko/native-types/blob/master/src/Matrix.php#L232-L276 ) Please share you thoughts about this. Best regards, Alexander пн, 23 мар. 2020 г. в 20:58, : > Hi internals, > > I have opened voting on > https://wiki.php.net/rfc/userspace_operator_overloading, which allows > users > to overload operators in their own classes. > > Voting closes on 2020-04-06. > > Regards, > Jan Böhmer > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: http://www.php.net/unsub.php > >
[PHP-DEV] Re: [VOTE] Userspace operator overloading
On 23.03.2020 at 18:58, jan.h.boeh...@gmx.de wrote: > I have opened voting on > https://wiki.php.net/rfc/userspace_operator_overloading, which allows users > to overload operators in their own classes. It seems to me that the RFC is not sufficiently specific enough regarding the concatenation of instances of classes which implement __toString(). The RFC itself doesn't mention that explicitly, and the backward incompatible changes section states: | As long as the user does not implement, the operator magic functions, | operators on objects will behave in the previous way. However, at least the current implementation raises two notices ("You have to implement the __concat function") when concatenating Stringable objects. A minor issue: in my opinion, introducing PHP_OPERAND_TYPES_NOT_SUPPORTED doesn't make sense. The RFC says: | Handlers can specify return typehints, but note that the return type | has to be nullable (as PHP_OPERAND_TYPES_NOT_SUPPORTED has the value | null). So if we ever wanted to change the value of PHP_OPERAND_TYPES_NOT_SUPPORTED, we'd introduce a BC break. Therefore the constant's value likely will never change, so using NULL directly to signal unsupported operand types would be fine, wouldn't it? -- Christoph M. Becker -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] [VOTE] Userspace operator overloading
> 1. This is exposing functionality that already exists for internal classes > 2. Because this just exposes existing functionality, the amount of > technical complexity this introduces is very small > > 3. As mentioned, this functionality already exists internally and is used > by GMP, where it works (imho) very well. > Thanks Nikita for the insights, that's really helpful. I'd suggest removing the "PHP_OPERAND_TYPES_NOT_SUPPORTED" constant and settle on null instead. The reason is visible in the RFC: `public static function __mul($lhs, $rhs): ?Vector3` - nothing else than null can be returned here when looking at the return type. Returning a const is just calling for "WTF" indirections IMHO. I'm still voting yes, hoping for this const to be removed after if the RFC passes, if it does :) Nicolas
Re: [PHP-DEV] Improving PHP's Object Egonomics: A broad analysis
> > https://hive.blog/php/@crell/improving-php-s-object-ergonomics Thanks Larry, that's a good way to move forward on these topics. I generally like the ideal of combining property declaration and > constructors. I've had this on my mind for a while already, and also > received the same suggestion from a couple of other people (I think Nicolas > was one of them?) I confirm: that'd be super useful to clean the boilerplate. > large enough that I will often go with a quick and simple ad-hoc array > structure rather than declaring an explicit value object type. Yes > The main concern, as others have already mentioned, is that these inline > declarations can end up being quite verbose, especially once attributes get > involved. > I don't share this concern with attributes: they mix without any ambiguity, which is what matters. No syntax is perfect, ppl that prefer the current way will still be able to use it. > Named parameters are a pretty tough topic. I think one of the main points > of contention is that they make the parameters names part of the API > contract, and as such also subject to LSP. Your proposal offers two > possible ways to side-step this: First, by making named parameters opt-in > with a special syntax {}. Second, by limiting them to constructors. The > latter variant still exposes parameter names in the API, but at least does > not require their preservation across inheritance, as constructors are > excluded from LSP. I'm somewhat torn on this, because it makes named > parameters unusable with the very large body of existing methods, and > introduces an inconsistency in which methods can use named params and which > don't. > I'd like to propose something on the topic. I'm adding object literals to the mix because that's another feature of the language that we're missing a lot IMHO. Actually, there is one existing syntax for objects: (object) [...] My proposal is to allow any class in the casting operator: (Foo) [...] By default, all keys of the casted array would map to properties (with an error when no matching property exists in the current visibility scope). We would then allow for a new constructor method, either: public function __create(array $values) or: public static function __create(array $values): static This method would take over the cast operator and decide how to construct an instance of such a class. There is one drawback: accepted keys are not documented. Sure, property declarations can give a big hint. But I think we can solve this issue later: it's not a blocker to still make things work nicely. Also, this issue already exists with all methods that accept an array of options - and we'll find a solution for those - either using docblocks (there are already ways to use them for that) or using attributes (would be the best of course, once we have them.) Note that this __create() method looks a lot like __unserialize(): it's just called at a different place, but the implementations could be essentially the same. Regarding the remainder, I think that all of readonly properties, > asymmetric visibility and property accessors have their place and value, > with some overlap between them. As you already mentioned, the previous > property accessors proposal also included asymettric visibility as a > special case, and that's how I would introduce it as well. > Máté suggested this syntax and it has my preference over the one you menton Larry: doubling the visibility keyword could be enough to express read+write access: public private $property; <= public read access, private write access However, I generally think that the main value really is the readonly > properties as proposed in the recent RFC. Nowadays, a large fraction of the > classes I use are immutable value objects, for which public readonly > properties provide a much closer match to the semantics I want. > > I think that the problem with with-er methods is just that: It's a problem > with with-er methods. It's what happens when you try to shove immutability > into something that is not actually being used in an immutable manner. > Don't pretend things are immutable when they aren't... > I think "withers" solve the problem of immutability in a very pragmatic and convenient way. Take e.g. "private": it can be bypassed using closure rebinding or reflection, and this is really useful, e.g. to build "friendship" relations between classes in the same package (like in C++). On the other side, "final" is a real pain when needing to write proxies/decorators. It just blocks extensibility for no technical reasons really. Let me explain: If as a consumer, I DO want to extend a class, nothing will prevent me to do so. There is always the last resort solution, which is patching the too restrictive source class, either using a fork or some code rewriting tool. Either way, what matters is who is in charge of dealing with the issues this might create. In both ways, what matters is that the original author
Re: [PHP-DEV] Re: [VOTE] Object-based token_get_all() alternative
Hello, internals team! I would like to propose to rename the PhpToken::getAll() method into the PhpToken::tokenize(string $source) or PhpToken::lex(string $source) to use a more meaningful verb word. After renaming, it will sound more natural: $tokenStream = PhpToken::tokenize($sourceCode) Best regards, Alexander пн, 23 мар. 2020 г. в 19:04, Larry Garfield : > On Mon, Mar 23, 2020, at 9:07 AM, Nikita Popov wrote: > > On Fri, Mar 6, 2020 at 10:33 AM Nikita Popov > wrote: > > > > > Hi internals, > > > > > > I've opened voting on https://wiki.php.net/rfc/token_as_object, which > > > adds a new object-based interface to the tokenizer. Voting closes on > > > 2020-03-20. > > > > > > > This RFC has been accepted unanimously, with 47 votes in favor. > > > > Based on the additional feedback in this thread, I'll also add a > > __toString() method that returns the value of $token->text, unless anyone > > has objects to that... > > > > Regards, > > Nikita > > As long as __toString() is overridable in subclasses, that seems fine to > me. > > --Larry Garfield > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: http://www.php.net/unsub.php > >
Re: [PHP-DEV] [VOTE] Userspace operator overloading
On Mon, Mar 23, 2020 at 6:58 PM wrote: > Hi internals, > > I have opened voting on > https://wiki.php.net/rfc/userspace_operator_overloading, which allows > users > to overload operators in their own classes. > > Voting closes on 2020-04-06. > > Regards, > Jan Böhmer > Thank you. I voted yes on this for similar reasons than Nikita. I think it is confusing to users why internal objects can overload these and userland can't. The simplicity of exposing this is another plus. The potential for misuse is a non issue for me, because essentially this applies to most features, especially with existing magic methods we have a precedent that we can build upon instead of "repressing use". > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: http://www.php.net/unsub.php > >
Re: [PHP-DEV] Improving PHP's Object Egonomics: A broad analysis
> > For details, see the full writeup: > > https://hive.blog/php/@crell/improving-php-s-object-ergonomics An excellent writeup, thank you Larry. Peter
Re: [PHP-DEV] [RFC] [DISCUSSION] Locale-independent float to string cast
I'm very sorry, I pressed the reply instead of reply all button, I hope this fixes it! I agree that these cases can go horribly wrong. However, my reasoning is > the following: > - if a piece of code currently relies on locale-independence (e.g. > automated data exports) then this > change wouldn't cause any breakage since a workaround has already been in > place there (e.g. the > programmers use var_export() instead of casting) > - if a piece of code relies on the locale-dependent string representation > of floats then there will be > a BC break, sure, however I believe that code isn't very sensitive to the > change in the vast majority of the > cases since that data is for presentation purposes only. > I know it's for presentation purpose only, sadly it's not used for just presentation code. It's being consumed and parsed by automated imports that expect a format different than `3.5`, because that's how it organically evolved. Even when it was meant only for presentation, the consumer expected the `3,5` format and will keep expecting this until we notify them of a change (and then it will probably still take weeks before this is fixed on their side). A lot of code that I've encountered is stuff like: ``` $csv .= $product->getPrice() . ';'; // older code I've seen come by $product = get_product($$var5); $csv .= $product['price'] . ';'; ``` As much as I'd like to see this fixed and always give a `3.5`, sadly that's not the case if you use a different locale. Going through thousands of files to fix this, is not going to be an easy task, especially not as this is often old enough to not be usable by static code analyzers. > Or do you have other locale-dependent use-cases in mind? I am sure there > are some but I think the number of the situations where the change is > problematic is less than what it first seems. > No, this is the only issue I personally see with it. However, the impact could be severe enough to not be able to upgrade to a new PHP version in the foreseeable future, thus I would like to see an upgrade path, one that tells you where it would've gone wrong, instead of turning the behavior on or off. If I can gather the logs and thus find usages, I can pro-actively start fixing where this would go wrong. I'll take a performance hit over a breakage. Performance penalty would only have to apply if the locale is set to something we know will change the outcome. Maybe it turns out this is a small issue, maybe it's a big issue... I can't tell because it's either upgrade & break, or upgrade & work in the proposed scenario. Some breakage may take weeks to find out because scripts run periodically. I fully understand that you don't see this as a big issue, and I really wish I could say the same. I can't vote, so I can't change the outcome, please consider my use-case when moving forward, thanks! Regards, Lynn