[PHP-DEV] [RFC] Pure intersection types

  113712
March 23, 2021 09:32 george.banyard@gmail.com ("G. P. B.")
Greetings internals,

I'm presenting a new RFC to add support for pure intersection types to PHP.

An intersection type A&B means that the value must be of type A and of type
B at the same time.

I'm calling this proposal pure intersection types as there would be no
possibility of mixing intersection and union types, I'm leaving this as a
future scope.

The current draft is located on GitHub:
https://github.com/Girgias/intersection-types
And the current implementation PR is:
https://github.com/php/php-src/pull/6799

Looking forward to the feedback.

Best regards,

George P. Banyard
  113713
March 23, 2021 09:39 ocramius@gmail.com (Marco Pivetta)
Hey George,
<http://ocramius.github.com/>
On Tue, Mar 23, 2021 at 10:32 AM G. P. B. banyard@gmail.com> wrote:

> Greetings internals, > > I'm presenting a new RFC to add support for pure intersection types to PHP. > > An intersection type A&B means that the value must be of type A and of type > B at the same time. > > I'm calling this proposal pure intersection types as there would be no > possibility of mixing intersection and union types, I'm leaving this as a > future scope. > > The current draft is located on GitHub: > https://github.com/Girgias/intersection-types > And the current implementation PR is: > https://github.com/php/php-src/pull/6799 > > Looking forward to the feedback. >
Overall, totally for this, even if it is just the "pure" form that does not yet support composite expressions. I suppose that `ReflectionIntersectionType` will likely be the most interesting part of it, potentially hardcoding `ReflectionIntersectionType#allowsNull()` as `false` for now? (analogous to https://www.php.net/manual/en/class.reflectionuniontype.php ) Greets, Marco Pivetta http://twitter.com/Ocramius http://ocramius.github.com/
  113715
March 23, 2021 13:14 larry@garfieldtech.com ("Larry Garfield")
On Tue, Mar 23, 2021, at 4:32 AM, G. P. B. wrote:
> Greetings internals, > > I'm presenting a new RFC to add support for pure intersection types to PHP. > > An intersection type A&B means that the value must be of type A and of type > B at the same time. > > I'm calling this proposal pure intersection types as there would be no > possibility of mixing intersection and union types, I'm leaving this as a > future scope. > > The current draft is located on GitHub: > https://github.com/Girgias/intersection-types > And the current implementation PR is: > https://github.com/php/php-src/pull/6799 > > Looking forward to the feedback. > > Best regards, > > George P. Banyard
I love this! Thanks, George! A few editorial notes: * Under "Duplicate and redundant types", the prose says "For example, if ''A'' and ''B'' are class aliases, then ''A&B'' remains a legal intersection type". The code sample after it, however, says it's an error. Please clarify. * Under "Adding and removing intersection types", there appears to be some broken code formatting. * The Reflection section still refers to "union" types. I assume that's because that section is still a WIP. * Under "Future Scope / Type Aliases", you refer to "number" as being an alias, but the code sample calls it "CountableIterator". Design notes: * Should we be planning ahead for some future where union and intersection types can be mixed and design the reflection API accordingly? I worry that if we have a ReflectionIntersectionType, and a ReflectionUnionType, that ReflectionIntersectionAndUnionType is just going to make both implementers and users table-flip. --Larry Garfield
  113718
March 23, 2021 14:05 someniatko@gmail.com (someniatko)
> Should we be planning ahead for some future where union and intersection types can be mixed and design the reflection API accordingly? I worry that if we have a ReflectionIntersectionType, and a ReflectionUnionType, that ReflectionIntersectionAndUnionType is just going to make both implementers and users table-flip.
As far as I understood, there is no need for any new "combination" `ReflectionType`-s. For e.g. "A|(B&C)". There should be a structure like this: ``` ReflectionUnionType#getTypes(): |-- ReflectionType |-- ReflectionIntersectionType#getTypes(): |-- ReflectionType |-- ReflectionType ```
March 23, 2021 14:24 george.banyard@gmail.com ("G. P. B.")
On Tue, 23 Mar 2021 at 13:14, Larry Garfield <larry@garfieldtech.com> wrote:

> On Tue, Mar 23, 2021, at 4:32 AM, G. P. B. wrote: > > Greetings internals, > > > > I'm presenting a new RFC to add support for pure intersection types to > PHP. > > > > An intersection type A&B means that the value must be of type A and of > type > > B at the same time. > > > > I'm calling this proposal pure intersection types as there would be no > > possibility of mixing intersection and union types, I'm leaving this as a > > future scope. > > > > The current draft is located on GitHub: > > https://github.com/Girgias/intersection-types > > And the current implementation PR is: > > https://github.com/php/php-src/pull/6799 > > > > Looking forward to the feedback. > > > > Best regards, > > > > George P. Banyard > > > I love this! Thanks, George! > > A few editorial notes: > > * Under "Duplicate and redundant types", the prose says "For example, if > ''A'' and ''B'' are class aliases, then ''A&B'' remains a legal > intersection type". The code sample after it, however, says it's an > error. Please clarify. >
Clarified to "runtime class aliases".
> * Under "Adding and removing intersection types", there appears to be some > broken code formatting. >
Indeed should be fixed now. * The Reflection section still refers to "union" types. I assume that's
> because that section is still a WIP. >
Correct, I completely forgot about the Reflection aspect up until I started writing the RFC by copying the union type one. I've removed mentions of union and hopefully have something which makes a bit more sense.
> * Under "Future Scope / Type Aliases", you refer to "number" as being an > alias, but the code sample calls it "CountableIterator". >
Indeed fixed.
> Design notes: > > * Should we be planning ahead for some future where union and intersection > types can be mixed and design the reflection API accordingly? I worry that > if we have a ReflectionIntersectionType, and a ReflectionUnionType, that > ReflectionIntersectionAndUnionType is just going to make both implementers > and users table-flip. > > --Larry Garfield >
Having looked at the current Reflection API for types I'm not sure something like this is necessary as pointed out by someniatko, it would provide a tree like structure by the nature of the current design. However, it might be of interest to know if other things should be added to this. Best regards, George P. Banyard
  113730
March 23, 2021 19:45 matthewmatthew@gmail.com (Matthew Brown)
On Tue, 23 Mar 2021 at 05:32, G. P. B. banyard@gmail.com> wrote:

> I'm calling this proposal pure intersection types as there would be no > possibility of mixing intersection and union types, I'm leaving this as a > future scope. >
Does this miss an opportunity, though? It's useful to be able to write A&B|null.
  113934
April 3, 2021 12:22 george.banyard@gmail.com ("G. P. B.")
On Tue, 23 Mar 2021 at 19:45, Matthew Brown <matthewmatthew@gmail.com>
wrote:

> On Tue, 23 Mar 2021 at 05:32, G. P. B. banyard@gmail.com> wrote: > >> I'm calling this proposal pure intersection types as there would be no >> possibility of mixing intersection and union types, I'm leaving this as a >> future scope. >> > > Does this miss an opportunity, though? It's useful to be able to write > A&B|null. >
Obviously this is less powerful than support for composite types where one can use both intersections and unions. I've tried implementing composite types without grouping here: https://github.com/Girgias/php-src/pull/8 But I'm hitting various issues and I'm far from confident that I'll be able to resolve them and add the variance check code before June so that this can reasonably get voted in for PHP 8.1. The end goal is support for composite types but I prefer to land a reasonably self contained feature in 8.1 then nothing at all. Internals might disagree with this and refuse the feature unless "complete" but if that's the case there is still time to "finish" it for another RFC. If someone else wants to work on adding support for composite types they are free to work based on my PR, or collaborate with me. I've also tidied up the RFC: https://github.com/Girgias/intersection-types Unless someone shows up to work on composite types, I'll probably bring this to a vote next week (if I don't forget about it). Best regards, George P. Banyard
  113942
April 3, 2021 20:41 azjezz@protonmail.com (Saif Eddin Gmati)
Personally, I am against the syntax used in the PR for composite
types( even tho i don't have voting powers ).

I would prefer a syntax similar to Hack, where you have to use parentheses to make things more explicit.

considering the following Hack code:


    interface A {}
    interface B {}
    interface C {}
    interface D {}
    interface E {}
    interface F {}

    function bar(
      ((A & F) | (((A & B) | (C & D)) & E)) $_foo
    ): void {}


In PHP, i would assuming i can just remove the parentheses and it would work as expected:


    https://twitter.com/azjezz/status/1373439678045683721 / https://twitter.com/azjezz/status/1373647148026322946

Regards,

Saif.


‐‐‐‐‐‐‐ Original Message ‐‐‐‐‐‐‐
On Saturday, April 3, 2021 1:22 PM, G. P. B. banyard@gmail.com> wrote:

> On Tue, 23 Mar 2021 at 19:45, Matthew Brown matthewmatthew@gmail.com > wrote: > > > On Tue, 23 Mar 2021 at 05:32, G. P. B. george.banyard@gmail.com wrote: > > > > > I'm calling this proposal pure intersection types as there would be no > > > possibility of mixing intersection and union types, I'm leaving this as a > > > future scope. > > > > Does this miss an opportunity, though? It's useful to be able to write > > A&B|null. > > Obviously this is less powerful than support for composite types where one > can use both intersections and unions. > > I've tried implementing composite types without grouping here: > https://github.com/Girgias/php-src/pull/8 > But I'm hitting various issues and I'm far from confident that I'll be able > to resolve them and add the variance check code before June so that this > can reasonably get voted in for PHP 8.1. > > The end goal is support for composite types but I prefer to land a > reasonably self contained feature in 8.1 then nothing at all. > Internals might disagree with this and refuse the feature unless "complete" > but if that's the case there is still time to "finish" it for another RFC.. > > If someone else wants to work on adding support for composite types they > are free to work based on my PR, or collaborate with me. > > I've also tidied up the RFC: https://github.com/Girgias/intersection-types > > Unless someone shows up to work on composite types, I'll probably bring > this to a vote next week (if I don't forget about it). > > Best regards, > > George P. Banyard
  114493
May 17, 2021 08:58 george.banyard@gmail.com ("G. P. B.")
Hello internals,

As we are getting closer to feature freeze I want to move this proposal
forward.
The RFC is now also on the wiki:
https://wiki.php.net/rfc/pure-intersection-types

Composite types are left out of scope as it seems they should be handled
with grouping (e.g. (A&B) | C ) and not relying on the precedence of the
union operator.

It should also be noted that to get this working there is some parser
hackery done to circumvent the fact the it cannot resolve the ambiguity
between & for an intersection type and & for by-ref arguments.

Best regards,

George P. Banyard
  114496
May 17, 2021 14:17 larry@garfieldtech.com ("Larry Garfield")
On Mon, May 17, 2021, at 3:58 AM, G. P. B. wrote:
> Hello internals, > > As we are getting closer to feature freeze I want to move this proposal > forward. > The RFC is now also on the wiki: > https://wiki.php.net/rfc/pure-intersection-types > > Composite types are left out of scope as it seems they should be handled > with grouping (e.g. (A&B) | C ) and not relying on the precedence of the > union operator. > > It should also be noted that to get this working there is some parser > hackery done to circumvent the fact the it cannot resolve the ambiguity > between & for an intersection type and & for by-ref arguments.
I am very much a fan. On the reflection front, am I correct that we'd end up with: abstract ReflectionType -- ReflectionNamedType (single type) -- ReflectionUnionType (basically an array of named types) -- ReflectionIntersectionType (basically an array of named types) Where ReflectionUnionType and ReflectionIntersectionType are basically the same API to decompose further. And should combined intersection/union types be added in the future, the impact would be that their getTypes() methods would return an array of some combination of ReflectionTypes, whereas right now you could rely on them being ReflectioNamedType. (But that also means one could build ahead for that already with a little recursion.) Am I following that correctly? --Larry Garfield
  114498
May 17, 2021 14:41 george.banyard@gmail.com ("G. P. B.")
On Mon, 17 May 2021 at 15:17, Larry Garfield <larry@garfieldtech.com> wrote:

> On the reflection front, am I correct that we'd end up with: > > abstract ReflectionType > -- ReflectionNamedType (single type) > -- ReflectionUnionType (basically an array of named types) > -- ReflectionIntersectionType (basically an array of named types) > > Where ReflectionUnionType and ReflectionIntersectionType are basically the > same API to decompose further. And should combined intersection/union > types be added in the future, the impact would be that their getTypes() > methods would return an array of some combination of ReflectionTypes, > whereas right now you could rely on them being ReflectioNamedType. (But > that also means one could build ahead for that already with a little > recursion.) > > Am I following that correctly? > > --Larry Garfield >
This is indeed correct. George P. Banyard
  114679
May 31, 2021 15:09 george.banyard@gmail.com ("G. P. B.")
Hello,

It has been two weeks since my last email and the only thing which has come
up are the tokenizer changes pointed out by Tyson.
To preserve BC I've aliased T_AMPERSAND with
T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG
This is also reflected in the RFC:
https://wiki.php.net/rfc/pure-intersection-types

I plan on opening voting on Wednesday.

Best regards,

George P. Banyard
  114695
June 2, 2021 19:06 george.banyard@gmail.com ("G. P. B.")
On Mon, 31 May 2021 at 16:09, G. P. B. banyard@gmail.com> wrote:

> Hello, > > It has been two weeks since my last email and the only thing which has > come up are the tokenizer changes pointed out by Tyson. > To preserve BC I've aliased T_AMPERSAND with > T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG > This is also reflected in the RFC: > https://wiki.php.net/rfc/pure-intersection-types > > I plan on opening voting on Wednesday. >
As it turned out I misunderstood Tyson, and I was asked to clarify the RFC there has been some changes to it again: - Addition of a "Motivation" section, which explains why Intersection are needed and superior to Interfaces extending multiple Interfaces - Expand why standard types are not supported, this includes self/static/parent - Split the variance rules into 2 bullet points - Remove the T_AMPERSAND As such I'm postponing the start of the voting to tomorrow. Best Regards, George P. Banyard