[RFC] Nullable intersection types

  115554
July 23, 2021 09:58 nicolas.grekas@gmail.com (Nicolas Grekas)
Hi everyone,

as proposed by Nikita and Joe, I'm submitting this late RFC for your
consideration for inclusion in PHP 8.1. Intersection types as currently
accepted are not nullable. This RFC proposes to make them so.

I wrote everything down about the reasons why here:
https://wiki.php.net/rfc/nullable_intersection_types

Please have a look and let me know what you think.

Have a nice read,

Nicolas
  115555
July 23, 2021 10:54 marandall@php.net (Mark Randall)
On 23/07/2021 10:58, Nicolas Grekas wrote:
> Hi everyone, > I wrote everything down about the reasons why here: > https://wiki.php.net/rfc/nullable_intersection_types
IMO we should require brackets and forbid not using them when combining unions and intersections. These types are already going to be confusing enough and we can likely save a fair amount of confusion and pain down the line by requiring the explicit brackets. Without wanting to bikeshed, let's just make sure we're set on () because whatever we choose here will be the defacto mechanism for declaring sub-types in PHP for the rest of eternity so it would need to be maximally compatible with everything we might want to do with them.
  115556
July 23, 2021 11:05 guilliam.xavier@gmail.com (Guilliam Xavier)
On Fri, Jul 23, 2021 at 11:58 AM Nicolas Grekas grekas@gmail.com>
wrote:

> Hi everyone, > > as proposed by Nikita and Joe, I'm submitting this late RFC for your > consideration for inclusion in PHP 8.1. Intersection types as currently > accepted are not nullable. This RFC proposes to make them so. > > I wrote everything down about the reasons why here: > https://wiki.php.net/rfc/nullable_intersection_types > > Please have a look and let me know what you think. > > Have a nice read, > > Nicolas >
Hi Nicolas, thank you for putting this up. Just two editorial notes: - "This is because any intersection that contains the null type is identical to the null type itself.": I don't think that `X&null` is the same as `null` but rather like `never` (i.e. the "bottom/empty" type, or simply "impossible/nonsensical/bogus")? - "Should brackets around the intersection be: not needed / mandatory / allow both styles": maybe clearer would be e.g. "forbidden / mandatory / optional (allow both styles)"? Regards, -- Guilliam Xavier
  115557
July 23, 2021 12:11 nicolas.grekas@gmail.com (Nicolas Grekas)
Le ven. 23 juil. 2021 à 13:05, Guilliam Xavier xavier@gmail.com>
a écrit :

> > On Fri, Jul 23, 2021 at 11:58 AM Nicolas Grekas grekas@gmail.com> > wrote: > >> Hi everyone, >> >> as proposed by Nikita and Joe, I'm submitting this late RFC for your >> consideration for inclusion in PHP 8.1. Intersection types as currently >> accepted are not nullable. This RFC proposes to make them so. >> >> I wrote everything down about the reasons why here: >> https://wiki.php.net/rfc/nullable_intersection_types >> >> Please have a look and let me know what you think. >> >> Have a nice read, >> >> Nicolas >> > > Hi Nicolas, thank you for putting this up. Just two editorial notes: > > - "This is because any intersection that contains the null type is > identical to the null type itself.": I don't think that `X&null` is the > same as `null` but rather like `never` (i.e. the "bottom/empty" type, or > simply "impossible/nonsensical/bogus")? > > - "Should brackets around the intersection be: not needed / mandatory / > allow both styles": maybe clearer would be e.g. "forbidden / mandatory / > optional (allow both styles)"? >
Thanks, I edited both to the following: - any intersections that contain the ''null'' type are identical to the ''never'' type. - Intersections should be: without brackets around / with brackets around / allow both styles
  115559
July 23, 2021 12:36 derick@php.net (Derick Rethans)
On Fri, 23 Jul 2021, Nicolas Grekas wrote:

> as proposed by Nikita and Joe, I'm submitting this late RFC for your=20 > consideration for inclusion in PHP 8.1. Intersection types as=20 > currently accepted are not nullable. This RFC proposes to make them=20 > so. >=20 > I wrote everything down about the reasons why here:=20 > https://wiki.php.net/rfc/nullable_intersection_types >=20 > Please have a look and let me know what you think.
From=20the RFC: =C2=ABTaking all these elements into account, the preferenc= e=20 of... and thus to use the "?X&Y" syntax=C2=BB. I think this would be a mistake. You touch upon operator precedence, and=20 needing to know whether | or & is higher, and inventing a new precedence=20 for ?. I would strongly advocate for not getting into the realm with any=20 operator precendence, but instead *require* parenthesis for any=20 combination. This gives the code reader and writer an immediate clue=20 about what the code does. Most coding standards also recommend this for=20 expressions in "if" statements and the like. I do however agree with Sara's =C2=ABover-delivering syntax that hasn't bee= n=20 entirely thought through=C2=BB point. It will take a lot longer to come up= =20 with a proposal to combine intersection and union types. That in combination that you're proposing this RFC after feature freeze,=20 while you've had four months to make this arguments as part of the "Pure=20 Intersection Types" RFC, I am currently not going to support this RFC=20 for inclusion into PHP 8.1. cheers, Derick --=20 PHP 7.4 Release Manager Host of PHP Internals News: https://phpinternals.news Like Xdebug? Consider supporting me: https://xdebug.org/support https://derickrethans.nl | https://xdebug.org | https://dram.io twitter: @derickr and @xdebug
  115560
July 23, 2021 13:10 nicolas.grekas@gmail.com (Nicolas Grekas)
> > as proposed by Nikita and Joe, I'm submitting this late RFC for your > > consideration for inclusion in PHP 8.1. Intersection types as > > currently accepted are not nullable. This RFC proposes to make them > > so. > > > > I wrote everything down about the reasons why here: > > https://wiki.php.net/rfc/nullable_intersection_types > > > > Please have a look and let me know what you think. > > From the RFC: «Taking all these elements into account, the preference > of... and thus to use the "?X&Y" syntax». > > I think this would be a mistake. You touch upon operator precedence, and > needing to know whether | or & is higher, and inventing a new precedence > for ?. > > I would strongly advocate for not getting into the realm with any > operator precendence, but instead *require* parenthesis for any > combination. This gives the code reader and writer an immediate clue > about what the code does. Most coding standards also recommend this for > expressions in "if" statements and the like. > > I do however agree with Sara's «over-delivering syntax that hasn't been > entirely thought through» point. It will take a lot longer to come up > with a proposal to combine intersection and union types. >
That's another reason why I prefer going with "?X&Y". The situation we have here is very close to what we had back in 2016 when nullable types were introduced: we figured out that nullability was very much needed now, so we went with a syntax that would not overlap with a possible future RFC for unions. IMHO, going with (X&Y)|null is forcing a future we know little about.
> That in combination that you're proposing this RFC after feature freeze, > while you've had four months to make this arguments as part of the "Pure > Intersection Types" RFC, I am currently not going to support this RFC > for inclusion into PHP 8.1.
I wish I could have spotted that this discussion was needed earlier. Still, this is important for 8.1 (IMHO). From the RFC:
> For userland, if this nullable capability were added to a later version of PHP, making a parameter nullable later would cause a BC break (or force
a major version bump when using semver.) Also this:
> When PHP 7.0 introduced scalar types, it was obvious that the special null type was missing as a way to declare that null was a possible return value.
PHP 7.1 added the “?foo” syntax to declare their nullability. This lesson from history tells us that the nullable type is special and very much needed in PHP. Nicolas
  115561
July 23, 2021 14:16 internals@lists.php.net ("Levi Morrison via internals")
On Fri, Jul 23, 2021 at 6:37 AM Derick Rethans <derick@php.net> wrote:
> > From the RFC: «Taking all these elements into account, the preference > of... and thus to use the "?X&Y" syntax». > > I think this would be a mistake. You touch upon operator precedence, and > needing to know whether | or & is higher, and inventing a new precedence > for ?. > > I would strongly advocate for not getting into the realm with any > operator precendence, but instead *require* parenthesis for any > combination. This gives the code reader and writer an immediate clue > about what the code does. Most coding standards also recommend this for > expressions in "if" statements and the like.
I also strongly advocate for always requiring parentheses whenever mixing unions and intersections, and I don't think the nullable shorthand should be omitted from this rule.
  115562
July 23, 2021 14:30 deleugyn@gmail.com (Deleu)
On Fri, Jul 23, 2021 at 2:36 PM Derick Rethans <derick@php.net> wrote:

> From the RFC: «Taking all these elements into account, the preference > of... and thus to use the "?X&Y" syntax». > > I think this would be a mistake. You touch upon operator precedence, and > needing to know whether | or & is higher, and inventing a new precedence > for ?. > > I would strongly advocate for not getting into the realm with any > operator precendence, but instead *require* parenthesis for any > combination. This gives the code reader and writer an immediate clue > about what the code does. Most coding standards also recommend this for > expressions in "if" statements and the like. > > I do however agree with Sara's «over-delivering syntax that hasn't been > entirely thought through» point. It will take a lot longer to come up > with a proposal to combine intersection and union types. > > That in combination that you're proposing this RFC after feature freeze, > while you've had four months to make this arguments as part of the "Pure > Intersection Types" RFC, I am currently not going to support this RFC > for inclusion into PHP 8.1. > > cheers, > Derick > > -- > PHP 7.4 Release Manager > Host of PHP Internals News: https://phpinternals.news > Like Xdebug? Consider supporting me: https://xdebug.org/support > https://derickrethans.nl | https://xdebug.org | https://dram.io > twitter: @derickr and @xdebug > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: https://www.php.net/unsub.php
These are precisely everything I think about this RFC. The only thing the RFC made clear is why it is easy to make an exception for null while still not providing a full mix of union and intersection. Maybe my memory is also really bad, but the RFC makes it seem like version 7.0 was a mistake to be learned from which isn't clear for me. I understand that introducing nullable intersection later will warrant a major version and I don't see a problem with that. Pure Intersection RFC was such a breeze vote precisely because it didn't involve the complexity of mixing with union. Part of that complexity is now being rushed after feature freeze. -- Marco Aurélio Deleu
  115563
July 23, 2021 14:48 kontakt@beberlei.de (Benjamin Eberlei)
On Fri, Jul 23, 2021 at 4:31 PM Deleu <deleugyn@gmail.com> wrote:

> On Fri, Jul 23, 2021 at 2:36 PM Derick Rethans <derick@php.net> wrote: > > > From the RFC: «Taking all these elements into account, the preference > > of... and thus to use the "?X&Y" syntax». > > > > I think this would be a mistake. You touch upon operator precedence, and > > needing to know whether | or & is higher, and inventing a new precedence > > for ?. > > > > I would strongly advocate for not getting into the realm with any > > operator precendence, but instead *require* parenthesis for any > > combination. This gives the code reader and writer an immediate clue > > about what the code does. Most coding standards also recommend this for > > expressions in "if" statements and the like. > > > > I do however agree with Sara's «over-delivering syntax that hasn't been > > entirely thought through» point. It will take a lot longer to come up > > with a proposal to combine intersection and union types. > > > > That in combination that you're proposing this RFC after feature freeze, > > while you've had four months to make this arguments as part of the "Pure > > Intersection Types" RFC, I am currently not going to support this RFC > > for inclusion into PHP 8.1. > > > > cheers, > > Derick > > > > -- > > PHP 7.4 Release Manager > > Host of PHP Internals News: https://phpinternals.news > > Like Xdebug? Consider supporting me: https://xdebug.org/support > > https://derickrethans.nl | https://xdebug.org | https://dram.io > > twitter: @derickr and @xdebug > > > > -- > > PHP Internals - PHP Runtime Development Mailing List > > To unsubscribe, visit: https://www.php.net/unsub.php > > > These are precisely everything I think about this RFC. The only thing the > RFC made clear is why it is easy to make an exception for null while still > not providing a full mix of union and intersection. > > Maybe my memory is also really bad, but the RFC makes it seem like version > 7.0 was a mistake to be learned from which isn't clear for me. I understand > that introducing nullable intersection later will warrant a major version > and I don't see a problem with that. Pure Intersection RFC was such a > breeze vote precisely because it didn't involve the complexity of mixing > with union. Part of that complexity is now being rushed after feature > freeze. >
As a maintainer of a large open source library, yes 7.0 was a problem due to the nullability missing for return types and was the reason why a lot of open source libraries jumped from minimum 5.4/5.5/5.6 directly to 7.1 to avoid breaking BC twice for classes/interfaces when a signature of the following kind was present: /** * @param string $foo * @return ?string */ function foo () { } php 7.0: foo(string $foo) {} php 7.1: foo(string $foo) : ?string {}
> -- > Marco Aurélio Deleu >
  115564
July 23, 2021 15:50 theodorejb@outlook.com (Theodore Brown)
On Friday, July 23, 2021 at 4:58 AM Nicolas Grekas grekas@gmail.com> wrote:

> Hi everyone, > > as proposed by Nikita and Joe, I'm submitting this late RFC for your > consideration for inclusion in PHP 8.1. Intersection types as currently > accepted are not nullable. This RFC proposes to make them so. > > I wrote everything down about the reasons why here: > https://wiki.php.net/rfc/nullable_intersection_types > > Please have a look and let me know what you think.
Hi Nicolas, Thanks for your work on this. The RFC states:
> the preference of the author of this RFC is to define “?” as having > a lower precedence than any other type-operator, and thus to use > the “?X&Y” syntax.
I also strongly believe this would be a mistake. When union types were introduced, it was explicitly decided not to use the `?(T1|T2)` syntax, for the following reason [1]:
> this notation is both rather awkward syntactically, and differs from > the well-established `T1|T2|null` syntax used by phpdoc comments. The > discussion feedback was overwhelmingly in favor of supporting the > `T1|T2|null` notation.
`?T` is a shorthand alias for `T|null`, and the alias cannot be used to add `null` to a union type. Although PHP doesn't yet support generalized union and intersection type combinations, this is almost certainly something we'll want to enable in the future (in fact, this very RFC is a step towards this). But if union types don't support the shorthand nullability syntax, and intersection types require it, how will the syntaxes be combined in the future? E.g. will we write `null | A & B | C` or will it be required to use something like `?A & B | C`? The latter is not only syntactically awkward but also very confusing. Since `|null` is the only supported syntax to add `null` to a union type, for consistency the same syntax should be used to add `null` to an intersection type. This will avoid confusion and inconsistency down the road if a future RFC enables more general union and intersection type combinations. It also avoids the need to define a precedence for the `?` type operator. As you note in the RFC, PHP already defines `|` as having a lower precedence than `&`, so `X & Y | null` can only be interpreted as `(X & Y) | null`. This is consistent with other languages such as TypeScript, where `A & B | C & D` is parsed as `(A & B) | (C & D)`. [2] Since precedence is already defined for this syntax consistently with other languages, I don't think it's necessary to require parentheses if we use the `A & B | null` syntax. Best regards, Theodore [1]: https://wiki.php.net/rfc/union_types_v2#nullable_union_types [2]: https://github.com/Microsoft/TypeScript/pull/3622
  115565
July 23, 2021 15:56 internals@lists.php.net ("Levi Morrison via internals")
> As you note in the RFC, PHP already defines `|` as having a lower > precedence than `&`, so `X & Y | null` can only be interpreted as > `(X & Y) | null`. This is consistent with other languages such as > TypeScript, where `A & B | C & D` is parsed as `(A & B) | (C & D)`. > [2] > > Since precedence is already defined for this syntax consistently with > other languages, I don't think it's necessary to require parentheses > if we use the `A & B | null` syntax.
I want to acknowledge and reject this. Few people keep the bitwise precedence information in their head. It's not worth it -- just require parenthesis.
  115566
July 23, 2021 16:06 pierre-php@processus.org (Pierre)
Le 23/07/2021 à 17:56, Levi Morrison via internals a écrit :
>> As you note in the RFC, PHP already defines `|` as having a lower >> precedence than `&`, so `X & Y | null` can only be interpreted as >> `(X & Y) | null`. This is consistent with other languages such as >> TypeScript, where `A & B | C & D` is parsed as `(A & B) | (C & D)`. >> [2] >> >> Since precedence is already defined for this syntax consistently with >> other languages, I don't think it's necessary to require parentheses >> if we use the `A & B | null` syntax. > I want to acknowledge and reject this. Few people keep the bitwise > precedence information in their head. It's not worth it -- just > require parenthesis. > I don't want to reject this, this is actually a very good point, do not
reinvent a syntax that works somewhere else. And in the end, I do find this readable. (I prey that people will use space in they types definitions to make it even more readable, but style is not a topic for this RFC.) Accumulating union and sum types is probably not something I'd do every day, so in the end, I'll probably always go and read the documentation each and every time. But for people that do, they'll get used to it fast enough I think. This behavior seems fine, at least I think it's fine, as long as the documentation is clear. Regards, -- Pierre
  115567
July 23, 2021 16:25 larry@garfieldtech.com ("Larry Garfield")
On Fri, Jul 23, 2021, at 11:06 AM, Pierre wrote:
> Le 23/07/2021 à 17:56, Levi Morrison via internals a écrit : > >> As you note in the RFC, PHP already defines `|` as having a lower > >> precedence than `&`, so `X & Y | null` can only be interpreted as > >> `(X & Y) | null`. This is consistent with other languages such as > >> TypeScript, where `A & B | C & D` is parsed as `(A & B) | (C & D)`. > >> [2] > >> > >> Since precedence is already defined for this syntax consistently with > >> other languages, I don't think it's necessary to require parentheses > >> if we use the `A & B | null` syntax. > > I want to acknowledge and reject this. Few people keep the bitwise > > precedence information in their head. It's not worth it -- just > > require parenthesis. > > > I don't want to reject this, this is actually a very good point, do not > reinvent a syntax that works somewhere else. And in the end, I do find > this readable. (I prey that people will use space in they types > definitions to make it even more readable, but style is not a topic for > this RFC.) > > Accumulating union and sum types is probably not something I'd do every > day, so in the end, I'll probably always go and read the documentation > each and every time. But for people that do, they'll get used to it fast > enough I think. > > This behavior seems fine, at least I think it's fine, as long as the > documentation is clear.
Requiring parenthesis now leaves the option open in the future to make them optional when doing full mixed types. Making them optional now requires that they be optional in the future when doing full mixed types. I vaguely recall there being some potential issue with making them optional for full mixed intersection/union types, but not the details. Either way, it's a not-small decision to make, and may have complicated implications for future work. It shouldn't be made on "eh, seems nicer" grounds in a post-freeze last minute RFC. Making it required now is the safer option, as it allows more flexibility in the future once someone tries to implement full union/intersection mixing. Making it optional later may still happen, I don't know, but it doesn't box us in to requiring it later. --Larry Garfield
  115568
July 23, 2021 16:28 pierre-php@processus.org (Pierre)
Le 23/07/2021 à 18:25, Larry Garfield a écrit :
> Requiring parenthesis now leaves the option open in the future to make them optional when doing full mixed types. > > Making them optional now requires that they be optional in the future when doing full mixed types. > > I vaguely recall there being some potential issue with making them optional for full mixed intersection/union types, but not the details. Either way, it's a not-small decision to make, and may have complicated implications for future work. It shouldn't be made on "eh, seems nicer" grounds in a post-freeze last minute RFC. > > Making it required now is the safer option, as it allows more flexibility in the future once someone tries to implement full union/intersection mixing. Making it optional later may still happen, I don't know, but it doesn't box us in to requiring it later.
This is a good point as well. Regards, -- Pierre
  115570
July 24, 2021 03:53 mike@newclarity.net (Mike Schinkel)
> On Jul 23, 2021, at 5:58 AM, Nicolas Grekas grekas@gmail.com> wrote: > > Hi everyone, > > as proposed by Nikita and Joe, I'm submitting this late RFC for your > consideration for inclusion in PHP 8.1. Intersection types as currently > accepted are not nullable. This RFC proposes to make them so. > > I wrote everything down about the reasons why here: > https://wiki.php.net/rfc/nullable_intersection_types > > Please have a look and let me know what you think. > > Have a nice read, > > Nicolas
It seems this RFC is actually trying to accomplish two(2) things: 1. Add typehints for nullable intersection types to PHP. 2. Get PHP to support a preferred syntax for type-hinting nullable intersection types. Further: A. There seems to be consensus on the value of #1. B. There seems to be consensus on using a syntax with parentheses for #1. C. There is a lot of pushback on #2. D. The desired syntax in #2 would reduce future flexibility, as Larry Garfield commented. Given both of these sets of assertions I would ask the RFC's author and proponents what would be a worse outcome? X. Getting typehints for nullable intersection types added to PHP, but not the desired syntax? Y. Not getting typehints for nullable intersection types added to PHP? When answering please consider that #X is the outcome that would not preclude possibly getting #2 at a future date. --------- Also, the entire discussion has claimed a "need" for nullable intersection types but AFAIIK they have been presented in completely abstract terms; i.e. no one has presented any real-world scenarios where they would actually use nullable intersection types. It might be helpful — or at least it would be for me — if the RFC could add two or three real-world example use-cases where the author and proponents would actually like to use nullable intersection types in their future PHP code. #jmtcw -Mike
  115571
July 24, 2021 04:42 tobias.nyholm@gmail.com (Tobias Nyholm)
> It seems this RFC is actually trying to accomplish two(2) things: > > 1. Add typehints for nullable intersection types to PHP. > 2. Get PHP to support a preferred syntax for type-hinting nullable intersection types.
Yes of course. You cannot really do #1 without #2. I agree with Nicolas that `?X&Y` makes more sense. You add ? before the type. If the type is scalar, a class or an intersection type should not matter. But I hear some technical arguments from Derick so I won’t argue against that. Im fine with the syntax: `X & Y | null` I don’t think parentheses should be required. From a mathematical perspective you want to add parentheses when you want to override the operation order. If you remove the parentheses and the expression has the same order of operations, then the parentheses is clearly not needed. @Larry makes an argument to keep them:
> Requiring parenthesis now leaves the option open in the future to make them optional when doing full mixed types.
I don’t understand why we should require something that is not needed simply because it would give us an option to remove it later… Could you elaborate why this is important? (Im probably missing something)
> Given both of these sets of assertions I would ask the RFC's author and proponents what would be a worse outcome?
I don’t see how this question is relevant. We are not seeking compromises at the moment. We are seeking the best technical solution to a technical issue.
> Also, the entire discussion has claimed a "need" for nullable intersection types but AFAIIK they have been presented in completely abstract terms; i.e. no one has presented any real-world scenarios where they would actually use nullable intersection types.
The “need” is covered by the discussion about PHP 7.0. See this post as an example: https://externals.io/message/115554#115563 <https://externals.io/message/115554#115563> —————— When reading my message above could make it sound like I am pessimistic. That is not true. I am excited about this change and I am happy PHP has a long feature freeze so issues like this can show up before the release. Regards, Tobias
> On 23 Jul 2021, at 20:53, Mike Schinkel <mike@newclarity.net> wrote: > >> On Jul 23, 2021, at 5:58 AM, Nicolas Grekas grekas@gmail.com> wrote: >> >> Hi everyone, >> >> as proposed by Nikita and Joe, I'm submitting this late RFC for your >> consideration for inclusion in PHP 8.1. Intersection types as currently >> accepted are not nullable. This RFC proposes to make them so. >> >> I wrote everything down about the reasons why here: >> https://wiki.php.net/rfc/nullable_intersection_types >> >> Please have a look and let me know what you think. >> >> Have a nice read, >> >> Nicolas > > It seems this RFC is actually trying to accomplish two(2) things: > > 1. Add typehints for nullable intersection types to PHP. > 2. Get PHP to support a preferred syntax for type-hinting nullable intersection types. > > Further: > > A. There seems to be consensus on the value of #1. > B. There seems to be consensus on using a syntax with parentheses for #1. > C. There is a lot of pushback on #2. > D. The desired syntax in #2 would reduce future flexibility, as Larry Garfield commented. > > Given both of these sets of assertions I would ask the RFC's author and proponents what would be a worse outcome? > > X. Getting typehints for nullable intersection types added to PHP, but not the desired syntax? > Y. Not getting typehints for nullable intersection types added to PHP? > > When answering please consider that #X is the outcome that would not preclude possibly getting #2 at a future date. > > --------- > > Also, the entire discussion has claimed a "need" for nullable intersection types but AFAIIK they have been presented in completely abstract terms; i.e. no one has presented any real-world scenarios where they would actually use nullable intersection types. > > It might be helpful — or at least it would be for me — if the RFC could add two or three real-world example use-cases where the author and proponents would actually like to use nullable intersection types in their future PHP code. > > #jmtcw > > -Mike
  115572
July 24, 2021 05:01 mike@newclarity.net (Mike Schinkel)
> On Jul 24, 2021, at 12:42 AM, Tobias Nyholm nyholm@gmail.com> wrote: > >> It seems this RFC is actually trying to accomplish two(2) things: >> >> 1. Add typehints for nullable intersection types to PHP. >> 2. Get PHP to support a preferred syntax for type-hinting nullable intersection types. > > Yes of course. You cannot really do #1 without #2. > > I agree with Nicolas that `?X&Y` makes more sense. You add ? before the type. If the type is scalar, a class or an intersection type should not matter. But I hear some technical arguments from Derick so I won’t argue against that. > > Im fine with the syntax: `X & Y | null` > I don’t think parentheses should be required. From a mathematical perspective you want to add parentheses when you want to override the operation order. If you remove the parentheses and the expression has the same order of operations, then the parentheses is clearly not needed. > > @Larry makes an argument to keep them: > >> Requiring parenthesis now leaves the option open in the future to make them optional when doing full mixed types. > > > I don’t understand why we should require something that is not needed simply because it would give us an option to remove it later… Could you elaborate why this is important? (Im probably missing something)
The difference is if we make the decision to use the `?X&Y` syntax and we later realize it was a mistake then we are stuck with it. OTOH if we use the (X&Y)|null syntax and later realize it is okay to also allow `?X&Y` PHP could later be changed to allow it. The later is the choice that manages future risk better.
>> Given both of these sets of assertions I would ask the RFC's author and proponents what would be a worse outcome? > > I don’t see how this question is relevant. We are not seeking compromises at the moment. We are seeking the best technical solution to a technical issue.
If you are not willing to compromise you will probably get nothing. It is relevant because I was trying to get you to ask yourself if you would be happier if you get half of what you want rather than none of what you want. Because there is a very real possibility you will get none of what you want if the RFC requires the syntax so many have objected to. BTW, I do not have a strong opinion either way, but since I see than many do have a strong opinion I was trying to play arbitrator between two sets of people who each have very entrenched opinions where their opinions are in conflict. If neither side will budge, nobody wins.
>> o, the entire discussion has claimed a "need" for nullable intersection types but AFAIIK they have been presented in completely abstract terms; i.e. no one has presented any real-world scenarios where they would actually use nullable intersection types. > > > The “need” is covered by the discussion about PHP 7.0. See this post as an example: https://externals.io/message/115554#115563 <https://externals.io/message/115554#115563> That message mentioned the need in abstract, but it did not provide any real-world examples. It claims that there were real-world examples, but did not show any.
That message was also not part of the RFC. Listen, I am trying to help make the RFC better to improve its chance of passing. If you don't want that, then I will just demure. -Mike
> > —————— > > When reading my message above could make it sound like I am pessimistic. That is not true. I am excited about this change and I am happy PHP has a long feature freeze so issues like this can show up before the release. > > Regards, > Tobias > > >> On 23 Jul 2021, at 20:53, Mike Schinkel <mike@newclarity.net <mailto:mike@newclarity.net>> wrote: >> >>> On Jul 23, 2021, at 5:58 AM, Nicolas Grekas grekas@gmail.com <mailto:nicolas.grekas@gmail.com>> wrote: >>> >>> Hi everyone, >>> >>> as proposed by Nikita and Joe, I'm submitting this late RFC for your >>> consideration for inclusion in PHP 8.1. Intersection types as currently >>> accepted are not nullable. This RFC proposes to make them so. >>> >>> I wrote everything down about the reasons why here: >>> https://wiki.php.net/rfc/nullable_intersection_types <https://wiki.php.net/rfc/nullable_intersection_types> >>> >>> Please have a look and let me know what you think. >>> >>> Have a nice read, >>> >>> Nicolas >> >> It seems this RFC is actually trying to accomplish two(2) things: >> >> 1. Add typehints for nullable intersection types to PHP. >> 2. Get PHP to support a preferred syntax for type-hinting nullable intersection types. >> >> Further: >> >> A. There seems to be consensus on the value of #1. >> B. There seems to be consensus on using a syntax with parentheses for #1. >> C. There is a lot of pushback on #2. >> D. The desired syntax in #2 would reduce future flexibility, as Larry Garfield commented. >> >> Given both of these sets of assertions I would ask the RFC's author and proponents what would be a worse outcome? >> >> X. Getting typehints for nullable intersection types added to PHP, but not the desired syntax? >> Y. Not getting typehints for nullable intersection types added to PHP? >> >> When answering please consider that #X is the outcome that would not preclude possibly getting #2 at a future date. >> >> --------- >> >> Also, the entire discussion has claimed a "need" for nullable intersection types but AFAIIK they have been presented in completely abstract terms; i.e. no one has presented any real-world scenarios where they would actually use nullable intersection types. >> >> It might be helpful — or at least it would be for me — if the RFC could add two or three real-world example use-cases where the author and proponents would actually like to use nullable intersection types in their future PHP code. >> >> #jmtcw >> >> -Mike >
  115573
July 24, 2021 05:33 tobias.nyholm@gmail.com (Tobias Nyholm)
>> @Larry makes an argument to keep them: >> >>> Requiring parenthesis now leaves the option open in the future to make them optional when doing full mixed types. >> >> >> I don’t understand why we should require something that is not needed simply because it would give us an option to remove it later… Could you elaborate why this is important? (Im probably missing something) > > The difference is if we make the decision to use the `?X&Y` syntax and we later realize it was a mistake then we are stuck with it. > > OTOH if we use the (X&Y)|null syntax and later realize it is okay to also allow `?X&Y` PHP could later be changed to allow it. > > The later is the choice that manages future risk better.
I thought Larry was discussing `X & Y | null` vs `(X & Y) | null`. I’ve dropped `?X&Y` because Derick had technical arguments against it. The way I see it, there is no benefit in requiring the parentheses in `(X & Y) | null`. I suggest we use `X & Y | null`.
>>> Given both of these sets of assertions I would ask the RFC's author and proponents what would be a worse outcome? >> >> I don’t see how this question is relevant. We are not seeking compromises at the moment. We are seeking the best technical solution to a technical issue. > > If you are not willing to compromise you will probably get nothing. > > It is relevant because I was trying to get you to ask yourself if you would be happier if you get half of what you want rather than none of what you want. > > Because there is a very real possibility you will get none of what you want if the RFC requires the syntax so many have objected to. > > BTW, I do not have a strong opinion either way, but since I see than many do have a strong opinion I was trying to play arbitrator between two sets of people who each have very entrenched opinions where their opinions are in conflict. If neither side will budge, nobody wins.
That is a strange attitude. You are saying that you rather see a release with a know flaw than actually trying to find the best solution. The release will be in 4 months. There is a process to clearly find issues like this. There is plenty of time to review this RFC and release it in beta 2 and let people test it. This is not a last minute thing, the process is designed for this.
>>> o, the entire discussion has claimed a "need" for nullable intersection types but AFAIIK they have been presented in completely abstract terms; i.e. no one has presented any real-world scenarios where they would actually use nullable intersection types. >> >> >> The “need” is covered by the discussion about PHP 7.0. See this post as an example: https://externals.io/message/115554#115563 <https://externals.io/message/115554#115563> > That message mentioned the need in abstract, but it did not provide any real-world examples. It claims that there were real-world examples, but did not show any. > > That message was also not part of the RFC.
The first paragraph under “Rational” mentioned this: https://wiki.php.net/rfc/nullable_intersection_types#rationale <https://wiki.php.net/rfc/nullable_intersection_types#rationale> In my world maintaining PHP libraries, it is obvious that 7.0 was missing this feature. As Benjamin mentioned, you could see that all libraries that migrated from 5.x just skipped 7.0 and went straight to support 7.1. I did the same for all my packages because of this reason. I made a misstake to assume that everybody had the same “world of maintaining PHP libraries” as I do. So the “real world examples” you are looking for is: If we don’t merge a version of this RFC in 8.1, PHP packages will not take leverage of the inspection types until PHP 8.2. The reason for a package to drop PHP 7 support is to be able to use the cool features in PHP 8. This will require a major release (something all maintainer should do sparsely). Why would I do a new major release if I cannot properly define my API (interfaces)? I rather wait to next PHP version where I can express my API and do my major release then. As the RFC states and Benjamin made extra clear, this is exactly what happened with PHP 7.0.
> > Listen, I am trying to help make the RFC better to improve its chance of passing. If you don't want that, then I will just demure.
>
Sorry if I sounded (or keep sounding negative). I appriciate you and everybody else participate in this discussion. We are all trying to make PHP better and we are all trying to move this RFC forward. // Tobias
  115575
July 24, 2021 08:17 deleugyn@gmail.com (Deleu)
On Sat, Jul 24, 2021, 07:33 Tobias Nyholm nyholm@gmail.com> wrote:

> > >>> Given both of these sets of assertions I would ask the RFC's author > and proponents what would be a worse outcome? > >> > >> I don’t see how this question is relevant. We are not seeking > compromises at the moment. We are seeking the best technical solution to a > technical issue. >
The very essence of this whole RFC is rooted in compromise. This is a new feature being discussed after feature freeze. If best technical solution is what we should seek, then this discussion should target 8.2.
> > > That is a strange attitude. You are saying that you rather see a release > with a know flaw than actually trying to find the best solution. > The release will be in 4 months. There is a process to clearly find issues > like this. There is plenty of time to review this RFC and release it in > beta 2 and let people test it. This is not a last minute thing, the process > is designed for this.
Where does it say that feature freeze exists so that more features can be built after the freeze?
> > So the “real world examples” you are looking for is: > If we don’t merge a version of this RFC in 8.1, PHP packages will not take > leverage of the inspection types until PHP 8.2. > > As the RFC states and Benjamin made extra clear, this is exactly what > happened with PHP 7.0. >
And that's OK! Pure Intersection was voted that way 30 against 3 the way that it was! You can steer clear from intersection in libraries on 8.1 and use it on application code only, provide feedback and be part of a healthier discussion when extending its capabilities to cover what libraries need at a later stage.
  115576
July 24, 2021 13:11 mike@newclarity.net (Mike Schinkel)
> On Jul 24, 2021, at 1:33 AM, Tobias Nyholm nyholm@gmail.com> wrote: >> If you are not willing to compromise you will probably get nothing. >> >> It is relevant because I was trying to get you to ask yourself if you would be happier if you get half of what you want rather than none of what you want. >> >> Because there is a very real possibility you will get none of what you want if the RFC requires the syntax so many have objected to. >> >> BTW, I do not have a strong opinion either way, but since I see than many do have a strong opinion I was trying to play arbitrator between two sets of people who each have very entrenched opinions where their opinions are in conflict. If neither side will budge, nobody wins. > > > That is a strange attitude. You are saying that you rather see a release with a know flaw than actually trying to find the best solution. > The release will be in 4 months. There is a process to clearly find issues like this. There is plenty of time to review this RFC and release it in beta 2 and let people test it. This is not a last minute thing, the process is designed for this.
That is begging the question. It is not a "known flaw" — it is a perfectly fine option — it is just not your preference. Arguing the syntax is squarely in the realm of bike-shedding.
>> That message mentioned the need in abstract, but it did not provide any real-world examples. It claims that there were real-world examples, but did not show any. >> >> That message was also not part of the RFC. > > The first paragraph under “Rational” mentioned this: https://wiki.php.net/rfc/nullable_intersection_types#rationale <https://wiki.php.net/rfc/nullable_intersection_types#rationale> I see no code examples showing real-world use-cases in the "Rational" section, I just see an abstract assertion by the author explain why they believe it is needed.
I don't get the pushback on providing real-world use-case examples. Clearly with your work in Symfony — given the assumption that nullable intersection types are really needed — you must has at least a few examples. Why not provide them?
> In my world maintaining PHP libraries, it is obvious that 7.0 was missing this feature. As Benjamin mentioned, you could see that all libraries that migrated from 5.x just skipped 7.0 and went straight to support 7.1. I did the same for all my packages because of this reason. I made a misstake to assume that everybody had the same “world of maintaining PHP libraries” as I do.
My understanding from all interactions on this list is that posters saying that something is important is (almost?) never sufficient. Instead it is incumbent upon RFC authors and RFC supporters to go the extra mile and make a strong case for why something is needed. And thus far, I have not seen any actual cases where it is needed, I have only heard assertions. Note I am not against this. I tend to prefer more functionality in a language, not less. So by asking you to give examples I am actually trying to help you make your case. And it is puzzling to me why you are pushing back so hard when I ask for use-cases.
> So the “real world examples” you are looking for is: > If we don’t merge a version of this RFC in 8.1, PHP packages will not take leverage of the inspection types until PHP 8.2. The reason for a package to drop PHP 7 support is to be able to use the cool features in PHP 8. This will require a major release (something all maintainer should do sparsely). Why would I do a new major release if I cannot properly define my API (interfaces)? I rather wait to next PHP version where I can express my API and do my major release then.
That is not a real-world example of why nullable intersection types are really needed. That is an assertion about library maintainer's concerns who want nullable intersection types. It is not code nor does it have anything mention of how any use-cases where nullable intersection types would be applied.
> Sorry if I sounded (or keep sounding negative). I appriciate you and everybody else participate in this discussion. We are all trying to make PHP better and we are all trying to move this RFC forward.
Then give some actual examples instead of just repeating assertions that this is needed and if you don't get it you believe it will make your life more difficult as a library maintainer. There are tens of things that make my life difficult every day I program in PHP, but this list doesn't care about my own or any of our difficulties, it cares about real-world use-cases that would provide reason why a feature needs to be added to PHP. -Mike P.S. Also, what Deleu said.
  115577
July 24, 2021 15:34 krakjoe@gmail.com (Joe Watkins)
This is not a new feature. This is a detail of a feature that was not well
understood for whatever reason.

That is why we are willing to fix it after freeze.

I would ask anyone voting to vote on the basis of the detail and leave
timing to be the problem of release managers. Voting negatively because you
don't agree that we should fix it at this time might be considered harmful
(to the feature, which we already accepted).

Cheers
Joe

On Saturday, 24 July 2021, Mike Schinkel <mike@newclarity.net> wrote:

> > On Jul 24, 2021, at 1:33 AM, Tobias Nyholm nyholm@gmail.com> > wrote: > >> If you are not willing to compromise you will probably get nothing. > >> > >> It is relevant because I was trying to get you to ask yourself if you > would be happier if you get half of what you want rather than none of what > you want. > >> > >> Because there is a very real possibility you will get none of what you > want if the RFC requires the syntax so many have objected to. > >> > >> BTW, I do not have a strong opinion either way, but since I see than > many do have a strong opinion I was trying to play arbitrator between two > sets of people who each have very entrenched opinions where their opinions > are in conflict. If neither side will budge, nobody wins. > > > > > > That is a strange attitude. You are saying that you rather see a release > with a know flaw than actually trying to find the best solution. > > The release will be in 4 months. There is a process to clearly find > issues like this. There is plenty of time to review this RFC and release it > in beta 2 and let people test it. This is not a last minute thing, the > process is designed for this. > > That is begging the question. It is not a "known flaw" — it is a perfectly > fine option — it is just not your preference. Arguing the syntax is > squarely in the realm of bike-shedding. > > >> That message mentioned the need in abstract, but it did not provide any > real-world examples. It claims that there were real-world examples, but > did not show any. > >> > >> That message was also not part of the RFC. > > > > The first paragraph under “Rational” mentioned this: > https://wiki.php.net/rfc/nullable_intersection_types#rationale < > https://wiki.php.net/rfc/nullable_intersection_types#rationale> > I see no code examples showing real-world use-cases in the "Rational" > section, I just see an abstract assertion by the author explain why they > believe it is needed. > > I don't get the pushback on providing real-world use-case examples. > Clearly with your work in Symfony — given the assumption that nullable > intersection types are really needed — you must has at least a few > examples. Why not provide them? > > > In my world maintaining PHP libraries, it is obvious that 7.0 was > missing this feature. As Benjamin mentioned, you could see that all > libraries that migrated from 5.x just skipped 7.0 and went straight to > support 7.1. I did the same for all my packages because of this reason. I > made a misstake to assume that everybody had the same “world of maintaining > PHP libraries” as I do. > > My understanding from all interactions on this list is that posters saying > that something is important is (almost?) never sufficient. Instead it is > incumbent upon RFC authors and RFC supporters to go the extra mile and make > a strong case for why something is needed. And thus far, I have not seen > any actual cases where it is needed, I have only heard assertions. > > Note I am not against this. I tend to prefer more functionality in a > language, not less. So by asking you to give examples I am actually trying > to help you make your case. And it is puzzling to me why you are pushing > back so hard when I ask for use-cases. > > > So the “real world examples” you are looking for is: > > If we don’t merge a version of this RFC in 8.1, PHP packages will not > take leverage of the inspection types until PHP 8.2. The reason for a > package to drop PHP 7 support is to be able to use the cool features in PHP > 8. This will require a major release (something all maintainer should do > sparsely). Why would I do a new major release if I cannot properly define > my API (interfaces)? I rather wait to next PHP version where I can express > my API and do my major release then. > > That is not a real-world example of why nullable intersection types are > really needed. That is an assertion about library maintainer's concerns who > want nullable intersection types. > > It is not code nor does it have anything mention of how any use-cases > where nullable intersection types would be applied. > > > Sorry if I sounded (or keep sounding negative). I appriciate you and > everybody else participate in this discussion. We are all trying to make > PHP better and we are all trying to move this RFC forward. > > Then give some actual examples instead of just repeating assertions that > this is needed and if you don't get it you believe it will make your life > more difficult as a library maintainer. > > There are tens of things that make my life difficult every day I program > in PHP, but this list doesn't care about my own or any of our difficulties, > it cares about real-world use-cases that would provide reason why a feature > needs to be added to PHP. > > -Mike > > P.S. Also, what Deleu said. > >
  115578
July 24, 2021 19:47 internals@lists.php.net ("Levi Morrison via internals")
> That is a strange attitude. You are saying that you rather see a release with a [known] flaw than actually trying to find the best solution.
Sorry, but sometimes features take time either due to technical reasons (variance was difficult to get right this way), or due to disagreements in voters. Just as we added scalar and return types in 7.0 but nullable types came only in 7.1, I think it's fine to add pure intersection types in 8.1 and add the ability to mix unions and intersections in 8.2. Is it _ideal_? No, but I'd rather wait than rush something in. There has been a lot of disagreement in this proposal, and I personally don't feel comfortable including this in any form for 8.1 because of this. I would rather wait, and waiting has the advantage that we can get a cohesive proposal for it to work with all unions and intersections, and not just a special case.
  115580
July 24, 2021 21:31 larry@garfieldtech.com ("Larry Garfield")
On Sat, Jul 24, 2021, at 12:33 AM, Tobias Nyholm wrote:
> >> @Larry makes an argument to keep them: > >> > >>> Requiring parenthesis now leaves the option open in the future to make them optional when doing full mixed types. > >> > >> > >> I don’t understand why we should require something that is not needed simply because it would give us an option to remove it later… Could you elaborate why this is important? (Im probably missing something) > > > > The difference is if we make the decision to use the `?X&Y` syntax and we later realize it was a mistake then we are stuck with it. > > > > OTOH if we use the (X&Y)|null syntax and later realize it is okay to also allow `?X&Y` PHP could later be changed to allow it. > > > > The later is the choice that manages future risk better. > > I thought Larry was discussing `X & Y | null` vs `(X & Y) | null`. > I’ve dropped `?X&Y` because Derick had technical arguments against it. > > The way I see it, there is no benefit in requiring the parentheses in > `(X & Y) | null`. I suggest we use `X & Y | null`.
Let me expand on my previous point (though those who have restated it are essentially correct). 1) Full mixed intersection and union types is something that we want to do in the future; it may or may not happen in 8.2, but it's something that should be considered on the informal roadmap. 2) Therefore, IF nullable intersection types are added now, they MUST be added in a way that is future-compatible (syntactically) with full mixed types in the future, as nullable intersection types are by definition (in PHP) a reduced-scope form of mixed types. To do otherwise would create a needless inconsistency in the language. 3) The parsing logic for intersection types is already bonkers, and has to do some wonky shenanigans in order to work. 4) At this time, it is unclear if it will be *technically* possible to support `Foo&Bar|Baz` as a syntax. Whether it is desireable or not is subjective, but whether it is possible at all is an unknown at this point. Given the complexity already in place, it may not be possible, no matter how much anyone argues that it's "obvious" based on math. If the technical answer is no, then the desireability question is entirely irrelevant. 5) Point 4 means that we simply don't know if `X&Y|null` will be extensible to X&Y|Z. It may be; it may also be impossible or infeasible. Point 3 means I would be highly skeptical of that being the case, and thus we should assume it is not. 6) That means there are a couple of possible end-states, assuming X&Y|null is implemented now: A) X&Y|Z and (X&Y)|Z both work fine, whether Z is null or not. B) X&Y|Z works iff Z is null; if it's not, then you must do (X&Y)|Z. C) X&Y|null cannot remain supported once full mixed types are supported, at least not without still-more special casing and shenanigans. That means either breaking BC, never implementing full mixed types, or having a wonky one-off in the engine forever. D) Some other mechanism such as the sometimes discussed type aliases provides an alternate way to solve this problem. (Eg, you have to pre-define a complex type Foo = X&Y|Z, and then in a function signature you can type either Foo or ?Foo.) As of right now, *we do not know which of those will happen*. I think most would be fine with A as an outcome, but there is very significant risk of C happening, and C is a bad outcome. Even if B could be done with a minimum of engine wonkiness, it would still be a sub-ideal state from a developer point of view. And D is still a very open question that may complicate the whole situation further. Thus, IF nullable intersection types are supported now, we're basically guessing on whether it will be possible to support mixed types in the future without parentheses. If we guess that it will be possible, and we're right, spiffy! If we guess that it will be possible, and we're wrong, we're in case C above. This is the worst outcome. If we guess that it will not be possible, and we're right, spiffy! If we guess that it will not be possible, and we're wrong, then people using nullable intersection types get a bonus new feature along the way. Of those, the only not-happily-ever-after alternative is guessing the parens will be optional and being wrong. Everything else works out OK. Thus, we should guess that it will not be possible, as that can only lead to a positive outcome whether we're right or wrong. Based on the above logic, I will not be voting for this RFC if it does not include parens, as it is too risky given the open unknowns around what will be possible in the future. ------ Separate from the technical argument, the question of how necessary it is: The assertion that intersection types are useless without nullability is facetious and wrong. Are they more useful with nullability? Yes, I don't think that's really debatable. But not-useful is incorrect. PHP 7 scalar types *were* useful. They *did* get used. Just not in as many cases as they could have been. However, I still die a little inside every time I have a nullable argument/return. To me, nullable always means a design flaw, even if a small one. (I still use it, but I hate that I have to.) The overwhelming majority of my type declarations are not nullable, and so would work perfectly fine with intersection types. I have no data on just how many libraries skipped 7.0 as a target version, but to assert that "everyone" did so because of the lack of nullability is simply absurd. Here's a bunch of other perfectly good reasons why a library would have skipped 7..0 as a target, many of which I know projects did do: 1) PHP 7's unified variable syntax was a PITA to update to in some cases, as it's hard to test for. By the time projects really worked all that out, 7.1 was out anyway. 2) PHP 5.6 had an extra-long support lifespan, so there was less incentive to do so than usual. 3) Even today aggressively tracking new versions is unusual, based on the Composer stats. 6 years ago it was even less common. What is super common is for projects to skip several required versions all at once when doing larger overhauls. (That includes Symfony.) 4) Linux distributions come out less frequently than PHP versions, so they often skip over "officially supported" PHP versions. So yeah, to pin the entirely of PHP 7.1 seeing a larger uptick than 7.0 on nullability is an entirely nonsensical and unsupported claim. That may well have been true for some projects, but there is zero evidence that was the primary reason for most projects, or even a major reason at all. I'm not against adding nullable intersection types now, but the "8.1 will be useless otherwise" rhetoric being used to argue for it is inappropriate and unjustified. --Larry Garfield
  115574
July 24, 2021 06:43 jordan.ledoux@gmail.com (Jordan LeDoux)
I do not think this is strictly true. The issue that this RFC is running
into is that combination types between intersections and unions was
something that was avoided for the intersection types RFC. Not because the
authors never thought of it, but because the RFC would have become very
broad and encompassed many different discussions. But since the issue of
adding combination types *only* for null is now being presented, it seems
to me that a lot of people are taking the position that the syntax for it
should match what the future implementation of combination types is to
avoid confusion. I don't think that's an unreasonable position to take, and
the difficulty of that discussion perhaps illustrates why this wasn't
included in the original RFC.

> We are not seeking compromises at the moment. We are seeking the best technical solution to a technical issue.
But this presumes that the ONLY technical issue at hand is the ability to have nullable intersections. Intersections are only available for class types, you can't use intersections with scalars. The *best* technical solution since there are no scalars is for people to use classes which have a null state internally, or at least I could argue that's the case. (In fact I *did* argue that's the case in a previous thread.) I'm not even convinced that this is a technical issue at this point, so the idea that there's no need for compromise is rather strange to me. If the goal is to support nothing but nullable intersections, there's an entire programming pattern[1] to solve that concern. But as nulls have always just "worked" for most PHP developers, I *can* see the argument for it despite the fact that I think it promotes bad program design. I know that I will use intersection types with the null object pattern in my own libraries even if nullable intersection types are added. So given that it's a special case of combination types, it makes sense that people are at least *discussing* what combination types should look like longer term.
> I don’t understand why we should require something that is not needed simply because it would give us an option to remove it later…
The point (I think) that Larry was making is that the parentheses can always be made optional in the future, but if this is delivered without parentheses now, it will be very, very hard to make parenthesis mandatory later (BC break) if there is a reason to do so. What would that reason be? I'm not sure, because a full implementation and RFC for combination types hasn't been proposed yet So requiring parentheses places the fewest restrictions on the anticipated future RFC for combination types and allows the author to find the best technical solution to *that* issue. --- [1]: https://en.wikipedia.org/wiki/Null_object_pattern On Fri, Jul 23, 2021 at 9:43 PM Tobias Nyholm nyholm@gmail.com> wrote:
> > It seems this RFC is actually trying to accomplish two(2) things: > > > > 1. Add typehints for nullable intersection types to PHP. > > 2. Get PHP to support a preferred syntax for type-hinting nullable > intersection types. > > Yes of course. You cannot really do #1 without #2. > > I agree with Nicolas that `?X&Y` makes more sense. You add ? before the > type. If the type is scalar, a class or an intersection type should not > matter. But I hear some technical arguments from Derick so I won’t argue > against that. > > Im fine with the syntax: `X & Y | null` > I don’t think parentheses should be required. From a mathematical > perspective you want to add parentheses when you want to override the > operation order. If you remove the parentheses and the expression has the > same order of operations, then the parentheses is clearly not needed. > > @Larry makes an argument to keep them: > > > Requiring parenthesis now leaves the option open in the future to make > them optional when doing full mixed types. > > > I don’t understand why we should require something that is not needed > simply because it would give us an option to remove it later… Could you > elaborate why this is important? (Im probably missing something) > > > Given both of these sets of assertions I would ask the RFC's author and > proponents what would be a worse outcome? > > I don’t see how this question is relevant. We are not seeking compromises > at the moment. We are seeking the best technical solution to a technical > issue. > > > Also, the entire discussion has claimed a "need" for nullable > intersection types but AFAIIK they have been presented in completely > abstract terms; i.e. no one has presented any real-world scenarios where > they would actually use nullable intersection types. > > > The “need” is covered by the discussion about PHP 7.0. See this post as an > example: https://externals.io/message/115554#115563 < > https://externals.io/message/115554#115563> > > —————— > > When reading my message above could make it sound like I am pessimistic. > That is not true. I am excited about this change and I am happy PHP has a > long feature freeze so issues like this can show up before the release. > > Regards, > Tobias > > > > On 23 Jul 2021, at 20:53, Mike Schinkel <mike@newclarity.net> wrote: > > > >> On Jul 23, 2021, at 5:58 AM, Nicolas Grekas grekas@gmail.com> > wrote: > >> > >> Hi everyone, > >> > >> as proposed by Nikita and Joe, I'm submitting this late RFC for your > >> consideration for inclusion in PHP 8.1. Intersection types as currently > >> accepted are not nullable. This RFC proposes to make them so. > >> > >> I wrote everything down about the reasons why here: > >> https://wiki.php.net/rfc/nullable_intersection_types > >> > >> Please have a look and let me know what you think. > >> > >> Have a nice read, > >> > >> Nicolas > > > > It seems this RFC is actually trying to accomplish two(2) things: > > > > 1. Add typehints for nullable intersection types to PHP. > > 2. Get PHP to support a preferred syntax for type-hinting nullable > intersection types. > > > > Further: > > > > A. There seems to be consensus on the value of #1. > > B. There seems to be consensus on using a syntax with parentheses for > #1. > > C. There is a lot of pushback on #2. > > D. The desired syntax in #2 would reduce future flexibility, as Larry > Garfield commented. > > > > Given both of these sets of assertions I would ask the RFC's author and > proponents what would be a worse outcome? > > > > X. Getting typehints for nullable intersection types added to PHP, but > not the desired syntax? > > Y. Not getting typehints for nullable intersection types added to PHP? > > > > When answering please consider that #X is the outcome that would not > preclude possibly getting #2 at a future date. > > > > --------- > > > > Also, the entire discussion has claimed a "need" for nullable > intersection types but AFAIIK they have been presented in completely > abstract terms; i.e. no one has presented any real-world scenarios where > they would actually use nullable intersection types. > > > > It might be helpful — or at least it would be for me — if the RFC could > add two or three real-world example use-cases where the author and > proponents would actually like to use nullable intersection types in their > future PHP code. > > > > #jmtcw > > > > -Mike > >
  115579
July 24, 2021 21:03 drealecs@gmail.com (=?UTF-8?Q?Alexandru_P=C4=83tr=C4=83nescu?=)
On Fri, Jul 23, 2021, 11:58 Nicolas Grekas grekas@gmail.com> wrote:

> Hi everyone, > > as proposed by Nikita and Joe, I'm submitting this late RFC for your > consideration for inclusion in PHP 8.1. Intersection types as currently > accepted are not nullable. This RFC proposes to make them so. > > I wrote everything down about the reasons why here: > https://wiki.php.net/rfc/nullable_intersection_types > > Please have a look and let me know what you think. >
Given the discussion, I think it might be better to remove all other syntax alternatives other than (X&Y)|null. There are persons here that mentioned they wish to wait for 8.2 than agree with 2/3 on the feature where the syntax might not be the most forward compatible one. One alternative could be to agree on a voting scheme where there could be 3 options: - No. - Yes, but only with (X&Y)|null. - Yes, any syntax, with additional vote on preferred syntax aiming for 2/3 on the second or third option. Regards, Alex
  115586
July 26, 2021 14:14 pollita@php.net (Sara Golemon)
On Fri, Jul 23, 2021 at 4:58 AM Nicolas Grekas grekas@gmail.com>
wrote:

> https://wiki.php.net/rfc/nullable_intersection_types > > I've commented on the PR and in R11 a bit already, but I'd like to state my
position here for the record. I do see the value in having nullability, but I can't disagree enough with the `?X&Y` syntax no matter how technically right the argument about operator precedence is. Even ignoring that literally nobody carries around a complete operator precedence table in their head, we simply can't predict how making this decision now will impact future plans for combined intersection/union types. The same argument honestly goes for every other syntax proposed, including `(X&Y)|null` which is also prone to making things worse. Nullable intersection types *IS* an implementation of combined intersection/union types, even if a narrow one. Those have not been planned out or approved, and they're too broad to sneak in post feature freeze. Period. Let's take the coming months to flesh out the edge cases on combined types. Let's maybe even look into type aliasing, which may have the side effect of making combined types more readable (or maybe less, who knows!). Most importantly, let's accept the fact that PHP's release cycle is only 12 months and we had pandemics that lasted longer than that. Next year is right around the corner. TL;DR - I've decided my vote. -Sara
  115591
July 27, 2021 13:32 brendt@stitcher.io (Brent Roose)
Hi all

From a userland developer point of view:

- PHP 7.0 types were a pain because of non-nullable types, the feature only became really useful as of PHP 7.1
- I share many people's opinion that this falls in the category of oversight
- I think (A&B)|null is the only sensible way to go

Sidenote: weren't there any prior cases where an RFC was accepted only to have found out an oversight which resulted in that RFC to be postponed to the next release?

Kind regards
Brent

> On 26 Jul 2021, at 16:14, Sara Golemon <pollita@php.net> wrote: > > On Fri, Jul 23, 2021 at 4:58 AM Nicolas Grekas grekas@gmail.com> > wrote: > >> https://wiki.php.net/rfc/nullable_intersection_types >> >> > I've commented on the PR and in R11 a bit already, but I'd like to state my > position here for the record. I do see the value in having nullability, > but I can't disagree enough with the `?X&Y` syntax no matter how > technically right the argument about operator precedence is. Even ignoring > that literally nobody carries around a complete operator precedence table > in their head, we simply can't predict how making this decision now will > impact future plans for combined intersection/union types. The same > argument honestly goes for every other syntax proposed, including > `(X&Y)|null` which is also prone to making things worse. > > Nullable intersection types *IS* an implementation of combined > intersection/union types, even if a narrow one. Those have not been planned > out or approved, and they're too broad to sneak in post feature freeze. > Period. Let's take the coming months to flesh out the edge cases on > combined types. Let's maybe even look into type aliasing, which may have > the side effect of making combined types more readable (or maybe less, who > knows!). > > Most importantly, let's accept the fact that PHP's release cycle is only 12 > months and we had pandemics that lasted longer than that. Next year is > right around the corner. > > TL;DR - I've decided my vote. > > -Sara
  115593
July 27, 2021 15:03 rowan.collins@gmail.com (Rowan Tommins)
On 27/07/2021 14:32, Brent Roose wrote:
> From a userland developer point of view: > > - PHP 7.0 types were a pain because of non-nullable types, the feature only became really useful as of PHP 7.1
You're not the only person to say this, but I find it really hard to believe. If this was so urgent that the feature was "not really useful" without it, why did it take twelve years from the addition of type declarations in PHP 5.0 (for classes and interfaces) until the "?" notation in PHP 7.1? Possibly because a syntax to make them nullable *was* added in PHP 5.1 (SomeType $foo=null), which continued to work for all the types available in PHP 7.0. Or possibly because there were enough places where people wanted non-nullable parameters that the feature was useful even if it couldn't be used everywhere. I can understand wanting to reduce the number of disruptive changes you make to the code base, but whatever version you pick, you can think of something in the next version up that you could wait for instead. Off the top of my head, you could set your minimum to... * PHP 5.1, for the "array" type declaration * PHP 5.4, for the "callable" type declaration * PHP 7.0, for "int", "string", etc * PHP 7.1, for the "?" nullable notation and "void" * PHP 7.4, for typed properties * PHP 8.0, for union types * PHP 8.1, for pure intersection types * PHP 8.2, for ... maybe mixed union-and-intersection, maybe type aliases, who knows... Maybe 7.1 was a sweet spot for you in terms of cost-benefit; maybe 8.1 won't be, but maybe it wouldn't be even with nullable intersections, and 8.2 will be.
> Sidenote: weren't there any prior cases where an RFC was accepted only to have found out an oversight which resulted in that RFC to be postponed to the next release?
That's the opposite of what's being requested here - what's being requested is that an extra feature be added at the last minute, without any changes to the feature already agreed. To my knowledge nobody has so far suggested that the current implementation of intersection types should be removed until this is resolved, and I can't think of any reason why that would make sense. Regards, -- Rowan Tommins [IMSoP]
  115594
July 27, 2021 20:10 jordan.ledoux@gmail.com (Jordan LeDoux)
> - PHP 7.0 types were a pain because of non-nullable types, the feature only became really useful as of PHP 7.1
See, this keeps being said, but as another userland developer it's extremely confusing. The types in 7.0 were very useful, and I personally didn't notice at all that they were missing because I used something like function(int $var = null), which is how nulls had been marked before PHP 7. In fact, when 7.1 was released, none of the signatures changed in my code, they were just updated to a different syntax.
> - I share many people's opinion that this falls in the category of oversight
I don't see how, when the intersection types RFC was: - Named "pure intersection types", which to me can only mean that the authors were both aware that there were other integrations which may be suggested and were excluding them from scope. - It contained an explicit mention of this issue:
> This means it would *not* be possible to mix intersection and union types together such as A&B|C, this is left as a future scope.
I also am not seeing that opinion from "many people" in this thread. Are you referring to other people off-list who are discussing this? Jordan On Tue, Jul 27, 2021 at 6:32 AM Brent Roose <brendt@stitcher.io> wrote:
> Hi all > > From a userland developer point of view: > > - PHP 7.0 types were a pain because of non-nullable types, the feature > only became really useful as of PHP 7.1 > - I share many people's opinion that this falls in the category of > oversight > - I think (A&B)|null is the only sensible way to go > > Sidenote: weren't there any prior cases where an RFC was accepted only to > have found out an oversight which resulted in that RFC to be postponed to > the next release? > > Kind regards > Brent > > > On 26 Jul 2021, at 16:14, Sara Golemon <pollita@php.net> wrote: > > > > On Fri, Jul 23, 2021 at 4:58 AM Nicolas Grekas grekas@gmail.com > > > > wrote: > > > >> https://wiki.php.net/rfc/nullable_intersection_types > >> > >> > > I've commented on the PR and in R11 a bit already, but I'd like to state > my > > position here for the record. I do see the value in having nullability, > > but I can't disagree enough with the `?X&Y` syntax no matter how > > technically right the argument about operator precedence is. Even > ignoring > > that literally nobody carries around a complete operator precedence table > > in their head, we simply can't predict how making this decision now will > > impact future plans for combined intersection/union types. The same > > argument honestly goes for every other syntax proposed, including > > `(X&Y)|null` which is also prone to making things worse. > > > > Nullable intersection types *IS* an implementation of combined > > intersection/union types, even if a narrow one. Those have not been > planned > > out or approved, and they're too broad to sneak in post feature freeze. > > Period. Let's take the coming months to flesh out the edge cases on > > combined types. Let's maybe even look into type aliasing, which may have > > the side effect of making combined types more readable (or maybe less, > who > > knows!). > > > > Most importantly, let's accept the fact that PHP's release cycle is only > 12 > > months and we had pandemics that lasted longer than that. Next year is > > right around the corner. > > > > TL;DR - I've decided my vote. > > > > -Sara > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: https://www.php.net/unsub.php > >
  115595
July 27, 2021 20:29 andre@webkr.de (=?utf-8?Q?Andr=C3=A9_H=C3=A4nsel?=)
> In fact, when 7.1 was released, none of the signatures changed in my code, they were just > updated to a different syntax.
That by the way is only because of a specific compatibility behavior which is so confusing that I erroneously reported it as a bug: https://bugs.php.net/bug.php?id=80948
  115596
July 27, 2021 22:51 rowan.collins@gmail.com (Rowan Tommins)
On 27 July 2021 21:29:47 BST, "André Hänsel" <andre@webkr.de> wrote:
>> In fact, when 7.1 was released, none of the signatures changed in my >code, they were just >> updated to a different syntax. > >That by the way is only because of a specific compatibility behavior >which is so confusing >that I erroneously reported it as a bug: >https://bugs.php.net/bug.php?id=80948
I can see how it would be confusing if you're coming to PHP fresh in the last few years, but from version 5.1 though to version 7.0, that was the way you marked nullable parameter types. It's a "compatibility behavior" only in the sense that it wasn't immediately removed when the more flexible "?type" syntax was added in 7.1. Regards, -- Rowan Tommins [IMSoP]
  115597
July 28, 2021 01:13 pierre.php@gmail.com (Pierre Joye)
Good morning,

On Wed, Jul 28, 2021 at 5:52 AM Rowan Tommins collins@gmail.com> wrote:
> > On 27 July 2021 21:29:47 BST, "André Hänsel" <andre@webkr.de> wrote: > >> In fact, when 7.1 was released, none of the signatures changed in my > >code, they were just > >> updated to a different syntax. > > > >That by the way is only because of a specific compatibility behavior > >which is so confusing > >that I erroneously reported it as a bug: > >https://bugs.php.net/bug.php?id=80948 > > > I can see how it would be confusing if you're coming to PHP fresh in the last few years, but from version 5.1 though to version 7.0, that was the way you marked nullable parameter types. > > It's a "compatibility behavior" only in the sense that it wasn't immediately removed when the more flexible "?type" syntax was added in 7.1.
I get the feeling the nullable type syntax was not very well noticed by users when it came out. However it is not what is confusing I think. intersection, types on the other hand, are. I have yet to find usages so critical that we had to rush that in in an incomplete manner. I personally prefer how it is done in typescript, but same thought, I have yet to see good code design using them. ;) Best, -- Pierre @pierrejoye | http://www.libgd.org
  115598
July 28, 2021 03:02 jordan.ledoux@gmail.com (Jordan LeDoux)
Intersection types are very useful if you use composition over inheritance.
That is, in PHP, they are most useful when you are using multiple
interfaces and/or traits to represent different aspects of an object which
might be present. For example, using an actual library I maintain, I have a
concept of different number type objects.

NumberInterface - Anything that represents a cardinal number of any kind
will share this.
SimpleNumberInterface - Anything that represents a non-complex number will
share this.
DecimalInterface - Anything that is represented as a float/decimal will
share this.
FractionInterface - Anything that is represented with a numerator and
denominator will share this.
ComplexNumberInterface - Anything that has a non-zero real part and a
non-zero imaginary part will share this.

To correctly represent the return types for, say, the add() method on
Decimal, what I would *actually* return is something like
NumberInterface&SimpleNumberInterface&DecimalInterface. The add() method on
Fraction would instead return
NumberInterface&SimpleNumberInterface&FractionInterface.

Now, internally, the add() method has a check for whether there is an xor
relationship between real and imaginary parts of the two numbers. If there
is, then a complex number object is returned instead. This means that to
fully describe the return type of this function, the type would look like
this:

function add(NumberInterface $num): NumberInterface&(
(SimpleNumberInterface&DecimalInterface) |
(SimpleNumberInterface&FractionInterface) | ComplexNumberInterface)

It can return any combination of these depending on the combination of
types provided as arguments and being called. Now, if I got to just dictate
how this was implemented from my own userland perspective, I'd provide
typedefs and limit combination types to those. So, my ideal implementation
would like like:

typedef DecimalType =
NumberInterface&SimpleNumberInterface&DecimalInterface;
typedef FractionType =
NumberInterface&SimpleNumberInterface&FractionInterface;
typedef ComplexType = NumberInterface&ComplexNumberInterface;

function add(DecimalType|FractionType|ComplexType $num):
DecimalType|FractionType|ComplexType

But as I've mentioned earlier, none of this is really affected by
nullability. To me, that adds very little (though not nothing). Since it
accepts class types instead of classes themselves, I'd make an
OptionalInterface that provides the tools to return a null instance that
has useful information for the user of my library about why the object is
"null".

Full combination types between unions and intersections is something that I
would use heavily, but to me that means it should be implemented carefully
and thoughtfully.

As they are currently, I would use intersection types less often, but they
will still be useful in typed arguments.

I can provide actual github references to the code of mine that would
change if that would be helpful, but I wanted to provide a broad example of
how intersection types in general might be useful and how they might be
used.

Jordan

On Tue, Jul 27, 2021 at 6:14 PM Pierre Joye php@gmail.com> wrote:

> Good morning, > > On Wed, Jul 28, 2021 at 5:52 AM Rowan Tommins collins@gmail.com> > wrote: > > > > On 27 July 2021 21:29:47 BST, "André Hänsel" <andre@webkr.de> wrote: > > >> In fact, when 7.1 was released, none of the signatures changed in my > > >code, they were just > > >> updated to a different syntax. > > > > > >That by the way is only because of a specific compatibility behavior > > >which is so confusing > > >that I erroneously reported it as a bug: > > >https://bugs.php.net/bug.php?id=80948 > > > > > > I can see how it would be confusing if you're coming to PHP fresh in the > last few years, but from version 5.1 though to version 7.0, that was the > way you marked nullable parameter types. > > > > It's a "compatibility behavior" only in the sense that it wasn't > immediately removed when the more flexible "?type" syntax was added in 7.1. > > I get the feeling the nullable type syntax was not very well noticed > by users when it came out. However it is not what is confusing I > think. intersection, types on the other hand, are. I have yet to find > usages so critical that we had to rush that in in an incomplete > manner. I personally prefer how it is done in typescript, but same > thought, I have yet to see good code design using them. ;) > > Best, > -- > Pierre > > @pierrejoye | http://www.libgd.org > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: https://www.php.net/unsub.php > >
  115599
July 28, 2021 03:26 pierre.php@gmail.com (Pierre Joye)
Hi Jordan,

On Wed, Jul 28, 2021, 10:02 AM Jordan LeDoux ledoux@gmail.com>
wrote:

> Intersection types are very useful if you use composition over > inheritance. That is, in PHP, they are most useful when you are using > multiple interfaces and/or traits to represent different aspects of an > object which might be present. For example, using an actual library I > maintain, I have a concept of different number type objects. >
Thanks for the detailed explanation. I do use them for very specific things (similar to your examples, for shapes). However my question was more about the rush for it, those are not easy to implement nicely, given the actual use cases, I am not sure it was worth this hurry. And I have the same feeling for this discussion about nullable intersection. best, Pierre
>
  115600
July 28, 2021 06:55 deleugyn@gmail.com (Deleu)
On Wed, Jul 28, 2021, 05:26 Pierre Joye php@gmail.com> wrote:

> However my question was more about the rush for it, those are not easy to
> implement nicely, given the actual use cases, I am not sure it was worth > this hurry. And I have the same feeling for this discussion about nullable > intersection. >
My interpretation is slightly different. I saw the Pure Intersection RFC as a way to break down a very complex thing into smaller manageable chunks. Getting everything right at once would be hard. I look at it almost as an experimental feature coming to 8.1, if you will. In the grand scheme of things it's incomplete, but in the tech space it is one huge step taken that will settle in and give another year to try and cover more ground. In the meantime basic use cases can take advantage of the changes in place and experiment with it, see what else would be a nice addition in that work space.
>
  115592
July 27, 2021 14:45 a.leathley@gmx.net (Andreas Leathley)
On 23.07.21 11:58, Nicolas Grekas wrote:
> Hi everyone, > > as proposed by Nikita and Joe, I'm submitting this late RFC for your > consideration for inclusion in PHP 8.1. Intersection types as currently > accepted are not nullable. This RFC proposes to make them so. > > I wrote everything down about the reasons why here: > https://wiki.php.net/rfc/nullable_intersection_types > > Please have a look and let me know what you think.
I would suggest to only offer a vote on (A&B)|null being allowed - not because I personally believe in that option, but because there seems to be a lot of tension around being forward-compatible and finding a solution that is as "safe" as possible. I fear if there are multiple syntax options, the rate of no-votes will just be higher, and the RFC will have no chance. From a userland POV I do not think it matters much if for now it is (A&B)|null or A&B|null - the point should be that nullability is possible and can be defined in code. If extra brackets seems to be more future-proof, then why not. Having one clear RFC voting option (with no secondary syntax voting option) also seems the most honest, as if somebody agrees that nullability would be useful but would only accept one syntax choice, that seems impossible to represent, necessitating a no vote on the whole RFC.
  115601
July 28, 2021 07:29 nicolas.grekas@gmail.com (Nicolas Grekas)
as proposed by Nikita and Joe, I'm submitting this late RFC for your
> consideration for inclusion in PHP 8.1. Intersection types as currently > accepted are not nullable. This RFC proposes to make them so. > > I wrote everything down about the reasons why here: > https://wiki.php.net/rfc/nullable_intersection_types > > Please have a look and let me know what you think. >
Hi everyone, Thank you for the contributions made to the discussion so far. I'm mostly AFK these days, hiking in Greece. That gives me time to think about comments made here, among other things :) Given the strong opposition from some, I considered withdrawing the RFC. But since I also see some nice support, I decided not to: even if the proposal is rejected, everyone should have the right to express their opinion, and the vote is the only option to not let only the most vocal or the most eloquent decide for the others. For the same reason, I'm not going to restrict the voting options to (X&Y)|null as some requested. I will change my mind if we spot that some syntax would put us in a corner. But so far and while I tried to be as careful as possible, all syntax proposals are future-proof to me. I get that some have strong coding style preferences, but that doesn't make a technical argument. It's true that deciding to allow no brackets won't allow us to force them later on. By why would we *force* them in the first place? While you may not like relying on it, operator precedence is a nice thing. I would hate having to put brackets around every single expression in PHP. For types, there are only two to three operators: we don't have to remember the full precedence table. And only one precedence makes sense anyway, so it's easy to remember. I'm not advocating that we should forbid brackets. Actually I'm going to vote for allowing both with and without them, because I don't want to force my preferred coding style to others. I do have a preference for using the `?` operator. It is compact and nullability *is* a flag. I'm reviewing code that use foo|null|bar, other that use foo|bar|null. That makes reading the code harder. About its precedence, I explained why I didn't need to be creative in the RFC: `?` has to be the lowest precedence type-operator. Any other options would make no sense from a logical pov. It would be so sweet and consistent to be able to use it all the time to express the nullability flag. I would mind if we allowed both `?` and `|null` btw. Intersection types are a really useful addition to the language, please don't suggest I framed it otherwise. I just thought that they would be a lot less useful if they were not nullable, especially considering that they could be part of public signatures that have to be maintained with BC in mind. I'm happy that some agree with this and share their experience about it. Nullability is a special beast in PHP. We have a range of operators dedicated to it. That's also why I think it deserves special care, and why I think it's important to have this discussion before 8.1 is out. To me, the feature freeze is also useful for this: polishing features that are about to be released. I don't see us rushing here. Let's do a careful and rational analysis of the proposal and vote on the very asked question. We do have enough time. TL;DR: I'm carefully looking for blockers and I'm calling for more examples if you spotted one! Cheers, Nicolas
>
  115602
July 28, 2021 12:38 Danack@basereality.com (Dan Ackroyd)
On Wed, 28 Jul 2021 at 08:29, Nicolas Grekas grekas@gmail.com> wrote:
> Nullability is a special beast in PHP. We have a range of operators > dedicated to it. That's also why I think it deserves special care, and why > I think it's important to have this discussion before 8.1 is out.
Why does this change need to be done now, rather than wait for 8.2? I can't see a clear reason in the RFC and saying 'nullability is special' doesn't seem a clear reason either. If you think you'll only be able to use intersection types when they can be union'ed with null, then ... just wait until they are? Andreas Leathley wrote:
> Having one clear RFC voting option (with no > secondary syntax voting option) also seems the most honest, as if > somebody agrees that nullability would be useful but would only accept > one syntax choice, that seems impossible to represent, necessitating a > no vote on the whole RFC.
I strongly agree with this. Having a situation where people will want to change their primary vote, based on which option in a secondary vote is winning is a "not good" situation. Having syntax for a type system be chosen by a popularity contest, where many of the voters are not aware of the implications of the choices is also not good. RFC authors should be trying to pass an RFC they are sure is the right choice, not leaving important decisions up in the air. Larry Garfield wrote:
> Some other mechanism such as the sometimes discussed type > aliases provides an alternate way to solve this problem.
This is an important point and why trying to push changes to the type system through after feature freeze is a bad idea. The example in the RFC uses single letter class names; in my experience most classes have quite a few more letters in them than that. Trying to use intersection types with realistic class names leads to code like this, for a custom cache definition*. function foo(Get|GetOrDefault|Set|SetWithTTL|GetOrGenerate|Clear $cache) { ... } Which is pretty unreadable. I don't think I'll be using intersection types much until PHP has the capability to compose types. e.g. something similar to this: type SimpleCache = Get|GetOrDefault|Set|SetWithTTL|GetOrGenerate|Clear; function foo(SimpleCache $cache) { ... } At which point the need for being able to include nullability in the intersection type goes away. You can instead use the existing ability to indicate a type can be null: function foo(?SimpleCache $cache) { ... } So yeah....I agree that widespread adoption of intersection types might not happen in 8.1 but that's fine, and better than possibly implementing the wrong thing after feature freeze. Nicolas Grekas wrote:
> polishing features that are about to be released.
Changes to the type system are not polish. cheers Dan Ack * Custom cache definitions. The conversation that the PHP FIG had around caching was very contentious. Everyone involved has their own idea of what features absolutely had to be in the interface, and what stuff should be left out. Some people just needed 'get' and 'set', some people needed a moderately complex cache, and other people needed an 'enterprise' level cache system that has full thundering herd protection. Trying to come up with a single implementation that makes everyone happy was an inherently impossible task. Instead of that, defining individual interfaces for each of the methods, and then allowing people to implement/use as many as they want to, allows for interoperability without having a One True Cache to rule them all, and so avoids having a prize to be fought over. So something like: interface Get { public function get(string $key): mixed; } interface GetOrDefault { public function getOrDefault(string $key, mixed $default): mixed; } interface Set { public function set(string $key, mixed $value): void; } interface SetWithTTL { public function set(string $key, mixed $value): void; } interface GetOrGenerate { // Gets a key if it exists, or calls $fn to generate the value // and stores the value, before returning it. public function get(string $key, callable $fn): mixed; } interface Clear { public function clear(string $key): void; }
  115684
August 10, 2021 12:39 nicolas.grekas@gmail.com (Nicolas Grekas)
> On Wed, 28 Jul 2021 at 08:29, Nicolas Grekas grekas@gmail.com> > wrote: > > Nullability is a special beast in PHP. We have a range of operators > > dedicated to it. That's also why I think it deserves special care, and > why > > I think it's important to have this discussion before 8.1 is out. > > Why does this change need to be done now, rather than wait for 8.2? > > I can't see a clear reason in the RFC and saying 'nullability is > special' doesn't seem a clear reason either. If you think you'll only > be able to use intersection types when they can be union'ed with null, > then ... just wait until they are? >
I will wait if I don't have the choice, but as many others reported, the experience with 7.0 missing nullability was a pain. We can learn from past mistakes. In my opinion, we can do better than the "wait for 8.2" stance I'm hearing around and make intersection nullable - like every other type in PHP - right now while we first release it. More generally, I'm not in favor of shipping partial features based on hypothetical future improvements. We don't know the future. Eg type aliasing or generics are vaporware right now. One or both of them might never happen, for whatever reason.
> Andreas Leathley wrote: > > Having one clear RFC voting option (with no > > secondary syntax voting option) also seems the most honest, as if > > somebody agrees that nullability would be useful but would only accept > > one syntax choice, that seems impossible to represent, necessitating a > > no vote on the whole RFC. > > I strongly agree with this. > > Having a situation where people will want to change their primary > vote, based on which option in a secondary vote is winning is a "not > good" situation. > > Having syntax for a type system be chosen by a popularity contest, > where many of the voters are not aware of the implications of the > choices is also not good. >
I find it quite dismissing to refer to "voters" as a group that decides by "popularity contest" or that is "not aware of the implications of the choices". I do trust the voting process and I do think that the discussions we're having here on php-internals and related media are appropriate means to raise voters' awareness of the topics at a glance (I also think the voting process might be improved, but there's already a separate thread about that.) Instead of fearing others, let's discuss things and ensure we raised all points so that ppl can make an informed decision. After this discussion, I hope ppl will vote according to what they think is best for PHP as a whole, all questions included, and independently from the rest. That'd be the most honest thing to do IMHO, and the best for PHP (on this RFC or on any other.) RFC authors should be trying to pass an RFC they are sure is the right
> choice, not leaving important decisions up in the air. >
Because nobody raised any potential blocker with any of the proposed syntax, I'm confident that all voting options have equal future-proofness. The remaining is a matter of coding style preference. While as the author of the RFC I do have a preference for the "?" nullability flag, others have strong and different opinions about it. Since the primary motivation for this PR is to provide nullability for intersection types, I'll be fine with any syntax that is consensual eventually.
> Larry Garfield wrote: > > Some other mechanism such as the sometimes discussed type > > aliases provides an alternate way to solve this problem. > > This is an important point and why trying to push changes to the type > system through after feature freeze is a bad idea. > > The example in the RFC uses single letter class names; in my > experience most classes have quite a few more letters in them than > that. Trying to use intersection types with realistic class names > leads to code like this, for a custom cache definition*. > > function foo(Get|GetOrDefault|Set|SetWithTTL|GetOrGenerate|Clear $cache) { > ... > } > > Which is pretty unreadable. I don't think I'll be using intersection > types much until PHP has the capability to compose types. e.g. > something similar to this: > > type SimpleCache = Get|GetOrDefault|Set|SetWithTTL|GetOrGenerate|Clear; > > function foo(SimpleCache $cache) { > ... > } > > At which point the need for being able to include nullability in the > intersection type goes away. You can instead use the existing ability > to indicate a type can be null: > > function foo(?SimpleCache $cache) { > ... > } >
That's an excellent argument in favor of using "?" actually (syntax consistency and readability), thanks for pointing it out. I'd go as far as saying that type aliases should forbid making "null" part of them. That way, nullability would always be explicit in the local type, with an easy-to-spot nullability flag. So yeah....I agree that widespread adoption of intersection types
> might not happen in 8.1 but that's fine, and better than possibly > implementing the wrong thing after feature freeze. >
We're having this discussion to be sure that "wrong" won't happen, while the good will. And based on what was raised so far, I see only the good coming. Cheers, Nicolas
  115685
August 10, 2021 13:38 rowan.collins@gmail.com (Rowan Tommins)
On 10/08/2021 13:39, Nicolas Grekas wrote:
> I will wait if I don't have the choice, but as many others reported, the > experience with 7.0 missing nullability was a pain.
Apologies if you already did and I've forgotten, but could you please expand on what "pain" you are referring to here? Firstly, I'm guessing we're talking about return types here, since parameters have had types since 5.0, and nullable types since 5.1 with the "TypeName $foo = null" syntax? Secondly, do you mean you postponed your adoption of the feature, or was there some larger issue? Regards, -- Rowan Tommins [IMSoP]
  115693
August 11, 2021 12:09 nicolas.grekas+php@gmail.com (Nicolas Grekas)
> On 10/08/2021 13:39, Nicolas Grekas wrote: > > I will wait if I don't have the choice, but as many others reported, the > > experience with 7.0 missing nullability was a pain. > > Apologies if you already did and I've forgotten, but could you please > expand on what "pain" you are referring to here? >
I personally did not experience that pain because I just skipped 7.0, since it wouldn't allow expressing the nullable return types I had to express in the APIs I maintain. Firstly, I'm guessing we're talking about return types here, since
> parameters have had types since 5.0, and nullable types since 5.1 with > the "TypeName $foo = null" syntax? >
That's correct. And that made me realize I missed highlighting that the situation with intersection types is actually worse than the one we had in 7.0 vs 7.1. As of https://github.com/php/php-src/pull/7254, not only return types, but also *arguments* are affected by the non-nullable limitation. If the RFC doesn't pass, I would still be in favor of reverting that part of the PR. That would bring us a situation very similar to 7.0 vs 7.1, which was not ideal but still better.
> Secondly, do you mean you postponed your adoption of the feature, or was > there some larger issue? >
I postponed it (and others did, as reported by Benjamin and Tobias in a previous message.) Note that I'm not running this RFC for my own personal benefit. I'm running it because I care about making PHP (and each release of it) as good as possible. I will postpone adopting the feature if I don't have the choice. But until it's too late, I'm willing to engage in this topic because I think the current state is far from ideal for 8.1. The larger issue is that when used as a type on arguments, adding the nullability flag isn't possible without a BC breaking change. Regards, Nicolas
  115694
August 11, 2021 13:31 rowan.collins@gmail.com (Rowan Tommins)
On 11/08/2021 13:09, Nicolas Grekas wrote:
> > On 10/08/2021 13:39, Nicolas Grekas wrote: > > I will wait if I don't have the choice, but as many others > reported, the > > experience with 7.0 missing nullability was a pain. > > Apologies if you already did and I've forgotten, but could you please > expand on what "pain" you are referring to here? > > > I personally did not experience that pain because I just skipped 7.0, > since it wouldn't allow expressing the nullable return types I had to > express in the APIs I maintain.
Sorry, I'm still confused what the "pain" is *other than* feeling obliged to wait until 7.1.
> The larger issue is that when used as a type on arguments, adding the > nullability flag isn't possible without a BC breaking change.
I can't imagine many people will force a parameter to be non-nullable just to use the shiny new syntax, then re-allow nulls in a subsequent version. More likely, they will leave that parameter un-checked until the full type can be specified. There is also a lot of code out there which is either: * in stand-alone applications, so backwards compatibility has no meaning * in private libraries with a handful of uses, so bringing uses in line is trivial * in public libraries, but marked "private" or "final", or documented as "internal use only", and therefore not subject to compatibility guarantees
> But until it's too late, I'm willing to engage in this topic because I > think the current state is far from ideal for 8.1.
There are always more features we could add, and there will always be a judgement call of what versions of PHP a code base should support. If it was generally agreed that there was only one right way to implement nullable intersections, and it was a trivial change, then I'd support it as a "quick win"; but that doesn't seem to be the case. Regards, -- Rowan Tommins [IMSoP]
  115697
August 12, 2021 13:47 nicolas.grekas+php@gmail.com (Nicolas Grekas)
> On 11/08/2021 13:09, Nicolas Grekas wrote: > > > > On 10/08/2021 13:39, Nicolas Grekas wrote: > > > I will wait if I don't have the choice, but as many others > > reported, the > > > experience with 7.0 missing nullability was a pain. > > > > Apologies if you already did and I've forgotten, but could you please > > expand on what "pain" you are referring to here? > > > > > > I personally did not experience that pain because I just skipped 7.0, > > since it wouldn't allow expressing the nullable return types I had to > > express in the APIs I maintain. > > > Sorry, I'm still confused what the "pain" is *other than* feeling > obliged to wait until 7.1. >
Maybe others that read this can share their experience on the topic?
> The larger issue is that when used as a type on arguments, adding the > > nullability flag isn't possible without a BC breaking change. > > > I can't imagine many people will force a parameter to be non-nullable > just to use the shiny new syntax, then re-allow nulls in a subsequent > version. More likely, they will leave that parameter un-checked until > the full type can be specified. > > There is also a lot of code out there which is either: > > * in stand-alone applications, so backwards compatibility has no meaning > * in private libraries with a handful of uses, so bringing uses in line > is trivial > * in public libraries, but marked "private" or "final", or documented as > "internal use only", and therefore not subject to compatibility guarantees > > > > But until it's too late, I'm willing to engage in this topic because I > > think the current state is far from ideal for 8.1. > > > There are always more features we could add, and there will always be a > judgement call of what versions of PHP a code base should support. > > If it was generally agreed that there was only one right way to > implement nullable intersections, and it was a trivial change, then I'd > support it as a "quick win"; but that doesn't seem to be the case. >
It is a trivial change from a technical pov, that's why I submit it for 8.1. There's zero risk. Thanks for your feedback btw! Nicolas
  115604
July 29, 2021 05:10 brendt@stitcher.io (Brent Roose)
Hi internals

I wanted to apologise for the poor wording I used in my previous mail when I said "oversight". What I meant to say is what Nicolas described in his followup mail: feature freeze as a time to polish implementations. I personally consider nullability to be more of an implementation polishment, but I realise the syntax question makes it a more difficult question.

While my personal experience with 7.0 and the lack of nullability was really annoying, I'm sure we'll all survive if 8.1 doesn't include nullability support. 

I just wanted to clarify those points, sorry if my previous mail caused any inconvenience. 

Kind regards
Brent

> On 28 Jul 2021, at 09:29, Nicolas Grekas grekas@gmail.com> wrote: > > as proposed by Nikita and Joe, I'm submitting this late RFC for your >> consideration for inclusion in PHP 8.1. Intersection types as currently >> accepted are not nullable. This RFC proposes to make them so. >> >> I wrote everything down about the reasons why here: >> https://wiki.php.net/rfc/nullable_intersection_types >> >> Please have a look and let me know what you think. >> > > Hi everyone, > > Thank you for the contributions made to the discussion so far. I'm mostly > AFK these days, hiking in Greece. That gives me time to think about > comments made here, among other things :) > > Given the strong opposition from some, I considered withdrawing the RFC. > But since I also see some nice support, I decided not to: even if the > proposal is rejected, everyone should have the right to express their > opinion, and the vote is the only option to not let only the most vocal or > the most eloquent decide for the others. > > For the same reason, I'm not going to restrict the voting options to > (X&Y)|null as some requested. I will change my mind if we spot that some > syntax would put us in a corner. But so far and while I tried to be as > careful as possible, all syntax proposals are future-proof to me. I get > that some have strong coding style preferences, but that doesn't make a > technical argument. It's true that deciding to allow no brackets won't > allow us to force them later on. By why would we *force* them in the first > place? While you may not like relying on it, operator precedence is a nice > thing. I would hate having to put brackets around every single expression > in PHP. For types, there are only two to three operators: we don't have to > remember the full precedence table. And only one precedence makes sense > anyway, so it's easy to remember. I'm not advocating that we should forbid > brackets. Actually I'm going to vote for allowing both with and without > them, because I don't want to force my preferred coding style to others. > > I do have a preference for using the `?` operator. It is compact and > nullability *is* a flag. I'm reviewing code that use foo|null|bar, other > that use foo|bar|null. That makes reading the code harder. About its > precedence, I explained why I didn't need to be creative in the RFC: `?` > has to be the lowest precedence type-operator. Any other options would make > no sense from a logical pov. It would be so sweet and consistent to be able > to use it all the time to express the nullability flag. I would mind if we > allowed both `?` and `|null` btw. > > Intersection types are a really useful addition to the language, please > don't suggest I framed it otherwise. I just thought that they would be a > lot less useful if they were not nullable, especially considering that they > could be part of public signatures that have to be maintained with BC in > mind. I'm happy that some agree with this and share their experience about > it. > > Nullability is a special beast in PHP. We have a range of operators > dedicated to it. That's also why I think it deserves special care, and why > I think it's important to have this discussion before 8.1 is out. To me, > the feature freeze is also useful for this: polishing features that are > about to be released. I don't see us rushing here. > > Let's do a careful and rational analysis of the proposal and vote on the > very asked question. We do have enough time. > > TL;DR: I'm carefully looking for blockers and I'm calling for more examples > if you spotted one! > > Cheers, > Nicolas > >>
  115692
August 11, 2021 10:45 nicolas.grekas@gmail.com (Nicolas Grekas)
> Hi everyone, > > as proposed by Nikita and Joe, I'm submitting this late RFC for your > consideration for inclusion in PHP 8.1. Intersection types as currently > accepted are not nullable. This RFC proposes to make them so. > > I wrote everything down about the reasons why here: > https://wiki.php.net/rfc/nullable_intersection_types > > Please have a look and let me know what you think. > > Have a nice read, > > Nicolas >
For the record, I was suggested to add a few more words about reflection in the RFC. In "Proposal", I added this:
> On the reflection side, ''ReflectionIntersectionType::allowsNull()'' will return ''true''/''false'' depending on what the intersection type accepts.
In "Rationale", I added this:
> About reflection, one could imagine a more complex model based on a ''ReflectionIntersectionType'' nested inside a ''ReflectionUnionType''.
This RFC proposes to rely on ''ReflectionIntersectionType::allowsNull()'' instead. This is consistent with how ''T|null'' is returned without ''ReflectionUnionType'' wrapper, and is also simpler for userland to deal with.
  115696
August 12, 2021 13:44 nicolas.grekas@gmail.com (Nicolas Grekas)
> > Hi everyone, > > as proposed by Nikita and Joe, I'm submitting this late RFC for your > consideration for inclusion in PHP 8.1. Intersection types as currently > accepted are not nullable. This RFC proposes to make them so. > > I wrote everything down about the reasons why here: > https://wiki.php.net/rfc/nullable_intersection_types > > Please have a look and let me know what you think. >
Hi everyone, I think it's time to move on. I'm going to open the vote tomorrow. I'd still be happy to get more feedback before or during the vote! Nicolas