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
Hey George,
http://ocramius.github.com/
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/6799Looking 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
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/6799Looking 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
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>
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/6799Looking 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
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.
On Tue, 23 Mar 2021 at 19:45, Matthew Brown matthewmatthew@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
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 Tue, 23 Mar 2021 at 19:45, Matthew Brown matthewmatthew@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
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
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-typesComposite 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
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
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
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-typesI 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