[RFC] Pure intersection types

php.internals

Girgias

5 years ago
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

Marco Pivetta

5 years ago
Hey George, <http://ocramius.github.com/> On Tue, Mar 23, 2021 at 10:32 AM G. P. B. <george.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/

Larry Garfield

5 years ago
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

Илья Сомов

5 years ago
> 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<A|(B&C)>#getTypes(): |-- ReflectionType<A> |-- ReflectionIntersectionType<B&C>#getTypes(): |-- ReflectionType<B> |-- ReflectionType<C> ```

Girgias

5 years ago
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

Matthew Brown

5 years ago
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.

Girgias

5 years ago
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

azjezz

5 years ago
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: <?php interface A {} interface B {} interface C {} interface D {} interface E {} interface F {} function bar( A&F|A&B|C&D&E $_foo ): void {} However, this now allows `A&B`, which previous was not allowed, so the correct translation is: <?php interface A {} interface B {} interface C {} interface D {} interface E {} interface F {} function bar( A&F|A&B&E|C&D&E $_foo ): void {} which is way much more confusing, can lead to type errors, and be more repetitive ( e.g: `A & ( B | C )` vs `A & B | A & C` - `A` mentioned twice ) ref: 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. <george.banyard@gmail.com> wrote:

Girgias

5 years ago
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

Larry Garfield

5 years ago
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

Girgias

5 years ago
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

Girgias

5 years ago
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

Girgias

5 years ago
On Mon, 31 May 2021 at 16:09, G. P. B. <george.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