Type hints in array destructuring expressions

php.internals

Enno Woortmann

6 years ago
Hi together, as the voting for the "Type casting in array destructuring expressions" shows a clear direction to be declined (sad faces on my side, I really would've liked it as a feature completion of the casting feature set without the need for a really new syntax, as the parser also already coverred it, but ok, time to continue :D ), combined with a strong interest for the topic "type checks in array destructuring expressions" (as well in the discussion as in the vote) I've set up a first draft of an RFC covering this topic: https://wiki.php.net/rfc/typehint_array_desctructuring The discussion around the casting in array destructuring brought up the idea to perform regular type checks in array destructuring expressions. This RFC proposes a new syntax to type hint a variable inside an array destructuring expression: $data = [42, 'Example', 2002]; [int $id, string $data, int $year] = $data; The type hints behave identically to the type hints used in method signatures (compare https://wiki.php.net/rfc/scalar_type_hints_v5). This especially includes a behaviour depending on the strict_types directive. Additionally to scalar type hints also object type hints are possible. I've not yet started an implementation draft but I think this one will be more tricky than the type cast implementation approach. As the parser re-uses the array definition for array destructuring expressions (which also leads to the type cast implementation without touching the parser) adding type hints to the definition would also affect other parts of the language eg. something like: $x = [int $a, string $b]; would be parsed by the parser. I'm currently not able to grasp the impact of such a change. But that's another topic. Let's focus on the idea itself instead of the implementation first. Thoughts on the first draft? Cheers, Enno

Michał Brzuchalski

6 years ago
Hi Enno, czw., 16 kwi 2020 o 12:20 Enno Woortmann <enno.woortmann@web.de> napisał(a):
> Hi together, > > as the voting for the "Type casting in array destructuring expressions" > shows a clear direction to be declined (sad faces on my side, I really > would've liked it as a feature completion of the casting feature set > without the need for a really new syntax, as the parser also already > coverred it, but ok, time to continue :D ), combined with a strong > interest for the topic "type checks in array destructuring expressions" > (as well in the discussion as in the vote) I've set up a first draft of > an RFC covering this topic: > > https://wiki.php.net/rfc/typehint_array_desctructuring > > The discussion around the casting in array destructuring brought up the > idea to perform regular type checks in array destructuring expressions. > This RFC proposes a new syntax to type hint a variable inside an array > destructuring expression: > > $data = [42, 'Example', 2002]; > [int $id, string $data, int $year] = $data; > >
I fear that if you go that path people would automatically expect it to be possible to write: int $id = $data['id']; int $id = getIdFromData($data); And then expect the $id to behave more like typed property with type guard. At least this is me what would expect from putting a type in from of variable name like in array destructuring example. Why? Cause it has a type constraint in from of variable name just like typed properties have. Cheers, Michał Brzuchalski

Nicolas Grekas

6 years ago
> > https://wiki.php.net/rfc/typehint_array_desctructuring >
Thanks, Enno, I like it a lot! I hope the implementation won't find any blocker.
> I fear that if you go that path people would automatically expect it to be > possible to write: > > int $id = $data['id']; > int $id = getIdFromData($data); >
That would be a nice addition I guess - maybe for a separate RFC to keep the focus clear on this one.
> And then expect the $id to behave more like typed property with type guard. >
I would not expect the type guard on my side, like function arguments don't provide type guards and also because this is PHP: runtime checks slow down the engine. Thus I would expect this to be guarded by static type analyzers for ppl who care (I'm not sure it matters personally, see SSA transformations), and on assignation otherwise to balance perf vs runtime overhead. (Note that the expectation you describe is a valid one, I'm just explaining that a different expectation exists, and why) Nicolas

Michał Brzuchalski

6 years ago
Hi Nicolas, czw., 16 kwi 2020 o 12:48 Nicolas Grekas <nicolas.grekas+php@gmail.com> napisał(a):
> > > https://wiki.php.net/rfc/typehint_array_desctructuring >> > > Thanks, Enno, I like it a lot! > I hope the implementation won't find any blocker. > > > >> I fear that if you go that path people would automatically expect it to be >> possible to write: >> >> int $id = $data['id']; >> int $id = getIdFromData($data); >> > > That would be a nice addition I guess - maybe for a separate RFC to keep > the focus clear on this one. > > > >> And then expect the $id to behave more like typed property with type >> guard. >> > > I would not expect the type guard on my side, like function arguments > don't provide type guards and also because this is PHP: runtime checks slow > down the engine. Thus I would expect this to be guarded by static type > analyzers for ppl who care (I'm not sure it matters personally, see SSA > transformations), and on assignation otherwise to balance perf vs runtime > overhead. (Note that the expectation you describe is a valid one, I'm just > explaining that a different expectation exists, and why) > >
Agree this would slow things down but if it could be potentially type checked on the assignment with type constraint in front of the variable name I think that would be a neat feature. So to work as a function parameter but not like a typed property. Cheers, Michał Brzuchalski

Enno Woortmann

6 years ago
> Agree this would slow things down but if it could be potentially type > checked on the assignment with type constraint in front of the variable > name I think that would be a neat feature. > So to work as a function parameter but not like a typed property.
Hi Michał, A type check during the assignment is the intent of the proposal. I'll update the description to state this more explicit. As i wrote in the initial mail the implementation side is the one which is currently mostly unclear to me. To see which parts of the language would be affected by the change. I think if it's implemented in a central way each assignment could be affected by a type check. But as Nicolas stated that should be kept in a separate RFC if that's something we want to tackle further. Cheers, Enno

Guilliam Xavier

6 years ago
On Thu, Apr 16, 2020 at 12:20 PM Enno Woortmann <enno.woortmann@web.de> wrote:
> > Hi together, > > as the voting for the "Type casting in array destructuring expressions" > shows a clear direction to be declined (sad faces on my side, I really > would've liked it as a feature completion of the casting feature set > without the need for a really new syntax, as the parser also already > coverred it, but ok, time to continue :D ), combined with a strong > interest for the topic "type checks in array destructuring expressions" > (as well in the discussion as in the vote) I've set up a first draft of > an RFC covering this topic: > > https://wiki.php.net/rfc/typehint_array_desctructuring > > The discussion around the casting in array destructuring brought up the > idea to perform regular type checks in array destructuring expressions. > This RFC proposes a new syntax to type hint a variable inside an array > destructuring expression: > > $data = [42, 'Example', 2002]; > [int $id, string $data, int $year] = $data; > > The type hints behave identically to the type hints used in method > signatures (compare https://wiki.php.net/rfc/scalar_type_hints_v5). This > especially includes a behaviour depending on the strict_types directive. > > Additionally to scalar type hints also object type hints are possible. > > I've not yet started an implementation draft but I think this one will > be more tricky than the type cast implementation approach. As the parser > re-uses the array definition for array destructuring expressions (which > also leads to the type cast implementation without touching the parser) > adding type hints to the definition would also affect other parts of the > language eg. something like: > > $x = [int $a, string $b]; > > would be parsed by the parser. I'm currently not able to grasp the > impact of such a change. But that's another topic. > > Let's focus on the idea itself instead of the implementation first. > Thoughts on the first draft? > > Cheers, Enno > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: http://www.php.net/unsub.php >
Hi, thanks for proposing, I guess it could be useful (or convenient at least). Just 2 thoughts: - It has been requested several times on this list to stop using the wording "type hint" and instead write "type declaration" ;) - When I see this example in the RFC: ``` $years = [["now", 2020], ["future", 2021]]; foreach ($years as [string $description, int $year]) { ``` I immediately think of a similar: ``` $years = ["now" => 2020, "future" => 2021]; foreach ($years as string $description => int $year) { ``` or: ``` $foos = [new Foo("one"), new Foo("two")]; foreach ($foos as Foo $foo) { ``` Now I remember this has already been requested (e.g. https://externals.io/message/104485#104488), but that's not really the same use case, so I don't know if it could/should be included... Regards,
-- Guilliam Xavier

Enno Woortmann

6 years ago
Hi,
> - It has been requested several times on this list to stop using the > wording "type hint" and instead write "type declaration" ;)
I've updated the RFC to use the "type declaration" wording, thanks for the hint :)
> - When I see this example in the RFC: > ``` > $years = [["now", 2020], ["future", 2021]]; > foreach ($years as [string $description, int $year]) { > ``` > I immediately think of a similar: > ``` > $years = ["now" => 2020, "future" => 2021]; > foreach ($years as string $description => int $year) { > ``` > or: > ``` > $foos = [new Foo("one"), new Foo("two")]; > foreach ($foos as Foo $foo) { > ```
As the RFC tackles array destructuring expressions and not foreach loops (which is just an option to use array destructuring there) I think this is out of scope for the RFC. I've added it to the future scope section though as I think it would align with the current proposal. Thanks for the input! Cheers, Enno

Nikita Popov

6 years ago
On Thu, Apr 16, 2020 at 12:20 PM Enno Woortmann <enno.woortmann@web.de> wrote:
> Hi together, > > as the voting for the "Type casting in array destructuring expressions" > shows a clear direction to be declined (sad faces on my side, I really > would've liked it as a feature completion of the casting feature set > without the need for a really new syntax, as the parser also already > coverred it, but ok, time to continue :D ), combined with a strong > interest for the topic "type checks in array destructuring expressions" > (as well in the discussion as in the vote) I've set up a first draft of > an RFC covering this topic: > > https://wiki.php.net/rfc/typehint_array_desctructuring > > The discussion around the casting in array destructuring brought up the > idea to perform regular type checks in array destructuring expressions. > This RFC proposes a new syntax to type hint a variable inside an array > destructuring expression: > > $data = [42, 'Example', 2002]; > [int $id, string $data, int $year] = $data; > > The type hints behave identically to the type hints used in method > signatures (compare https://wiki.php.net/rfc/scalar_type_hints_v5). This > especially includes a behaviour depending on the strict_types directive. > > Additionally to scalar type hints also object type hints are possible. > > I've not yet started an implementation draft but I think this one will > be more tricky than the type cast implementation approach. As the parser > re-uses the array definition for array destructuring expressions (which > also leads to the type cast implementation without touching the parser) > adding type hints to the definition would also affect other parts of the > language eg. something like: > > $x = [int $a, string $b]; > > would be parsed by the parser. I'm currently not able to grasp the > impact of such a change. But that's another topic. > > Let's focus on the idea itself instead of the implementation first. > Thoughts on the first draft? >
As you say, this syntax will likely run into parsing issues. Once you take into account that types aren't just "int", but also "Foo|Bar", and also consider that we have support for references in unpacking, you could be left with something like [int|float &$foo] = $bar; Without actually testing, I would expect that this is going to run into issues of similar difficulty as the arrow function proposal encountered. Rather than integrating this into the destructuring assignment syntax, I think it would be more helpful to view this as the infallible variant of pattern matching, which is also being discussed in the "match expression" thread. As suggested there, the syntax could be something like let [int|float $foo] = $bar; and would throw if the RHS does not satisfy the pattern on the LHS (unlike the match variant, which is fallible). I think this might help to bring things under one umbrella, and to draw a clearer line between this functionality and typed variables (if it's just a pattern guard, then it's expected that the type restriction is checked instantaneous, not enforced persistently.) Nikita

Enno Woortmann

6 years ago
Am 16.04.2020 um 16:50 schrieb Nikita Popov:
> As you say, this syntax will likely run into parsing issues. Once you take > into account that types aren't just "int", but also "Foo|Bar", and also > consider that we have support for references in unpacking, you could be > left with something like > > [int|float &$foo] = $bar; > > Without actually testing, I would expect that this is going to run into > issues of similar difficulty as the arrow function proposal encountered. > > Rather than integrating this into the destructuring assignment syntax, I > think it would be more helpful to view this as the infallible variant of > pattern matching, which is also being discussed in the "match expression" > thread. As suggested there, the syntax could be something like > > let [int|float $foo] = $bar; > > and would throw if the RHS does not satisfy the pattern on the LHS (unlike > the match variant, which is fallible). > > I think this might help to bring things under one umbrella, and to draw a > clearer line between this functionality and typed variables (if it's just a > pattern guard, then it's expected that the type restriction is checked > instantaneous, not enforced persistently.) > > Nikita
Hi Nikita, thanks for your response and your assessment concerning the parser change. I've played a bit around with the idea and came to the conclusion that changes like these are far beyond my knowledge of the code base and my C skills. Consequently I will not continue working on this idea as it moves away from my initial idea to simply cast values. If anyone wants to take this RFC draft, feel free to tackle this topic further. The secondary voting of the "casting in array destructuring expressions RFC" which will be closed in two days shows some interest into this topic. Cheers, Enno