When you follow ISP, you probably would have a lot of interfaces.
Thus, client code may require an object to implement a bunch of interfaces
depending on functionality needed.
Consider class Bar
:
interface A {}
interface B {}
interface C {}
interface D {}
interface E {}
class Bar implements A, B, C, D, E {
//
}
And some code, which uses Bar
, but depends rather on interfaces, which
functionality is actually needed:
function foo(A & B & E $object) {
// some work
var_dump($object);
}
It is currently feasable like this (ugly):
function foo(A $object) {
(function(B $object) {
(function(E $object) {
// some work
var_dump($object);
})($object);
})($object);
}
Or like this (more readable, but still):
function foo(A | B | E $object) {
if (!$object instanceof A) {
throw new \RuntimeException();
}
if (!$object instanceof B) {
throw new \RuntimeException();
}
if (!$object instanceof E) {
throw new \RuntimeException();
}
// some work
var_dump($object);
}
Another possible option is to create interface, which combines A
, B
,
E
, but in some cases it would lead us to interfaces explosion.
This idea proposes to eliminate instanceof
checks by introducing &
union operator.
2020-11-07 15:12 GMT, Eugene Sidelnyk zsidelnik@gmail.com:
When you follow ISP, you probably would have a lot of interfaces.
Thus, client code may require an object to implement a bunch of interfaces
depending on functionality needed.Consider class
Bar
:interface A {} interface B {} interface C {} interface D {} interface E {} class Bar implements A, B, C, D, E { // }
And some code, which uses
Bar
, but depends rather on interfaces, which
functionality is actually needed:function foo(A & B & E $object) { // some work var_dump($object); }
It is currently feasable like this (ugly):
function foo(A $object) { (function(B $object) { (function(E $object) { // some work var_dump($object); })($object); })($object); }
Or like this (more readable, but still):
function foo(A | B | E $object) { if (!$object instanceof A) { throw new \RuntimeException(); } if (!$object instanceof B) { throw new \RuntimeException(); } if (!$object instanceof E) { throw new \RuntimeException(); } // some work var_dump($object); }
Another possible option is to create interface, which combines
A
,B
,
E
, but in some cases it would lead us to interfaces explosion.This idea proposes to eliminate
instanceof
checks by introducing&
union operator.
You mean intersections? Psalm supports this notation.
Yes.
And I think it will be good if enforced by language.
2020-11-07 15:12 GMT, Eugene Sidelnyk zsidelnik@gmail.com:
When you follow ISP, you probably would have a lot of interfaces.
Thus, client code may require an object to implement a bunch of
interfaces
depending on functionality needed.Consider class
Bar
:interface A {} interface B {} interface C {} interface D {} interface E {} class Bar implements A, B, C, D, E { // }
And some code, which uses
Bar
, but depends rather on interfaces, which
functionality is actually needed:function foo(A & B & E $object) { // some work var_dump($object); }
It is currently feasable like this (ugly):
function foo(A $object) { (function(B $object) { (function(E $object) { // some work var_dump($object); })($object); })($object); }
Or like this (more readable, but still):
function foo(A | B | E $object) { if (!$object instanceof A) { throw new \RuntimeException(); } if (!$object instanceof B) { throw new \RuntimeException(); } if (!$object instanceof E) { throw new \RuntimeException(); } // some work var_dump($object); }
Another possible option is to create interface, which combines
A
,B
,
E
, but in some cases it would lead us to interfaces explosion.This idea proposes to eliminate
instanceof
checks by introducing&
union operator.You mean intersections? Psalm supports this notation.
https://wiki.php.net/rfc/intersection_types
2020-11-07 16:37 GMT+01:00, Eugene Sidelnyk zsidelnik@gmail.com:
Yes.
And I think it will be good if enforced by language.2020-11-07 15:12 GMT, Eugene Sidelnyk zsidelnik@gmail.com:
When you follow ISP, you probably would have a lot of interfaces.
Thus, client code may require an object to implement a bunch of
interfaces
depending on functionality needed.Consider class
Bar
:interface A {} interface B {} interface C {} interface D {} interface E {} class Bar implements A, B, C, D, E { // }
And some code, which uses
Bar
, but depends rather on interfaces,
which
functionality is actually needed:function foo(A & B & E $object) { // some work var_dump($object); }
It is currently feasable like this (ugly):
function foo(A $object) { (function(B $object) { (function(E $object) { // some work var_dump($object); })($object); })($object); }
Or like this (more readable, but still):
function foo(A | B | E $object) { if (!$object instanceof A) { throw new \RuntimeException(); } if (!$object instanceof B) { throw new \RuntimeException(); } if (!$object instanceof E) { throw new \RuntimeException(); } // some work var_dump($object); }
Another possible option is to create interface, which combines
A
,
B
,
E
, but in some cases it would lead us to interfaces explosion.This idea proposes to eliminate
instanceof
checks by introducing&
union operator.You mean intersections? Psalm supports this notation.
2020-11-07 15:12 GMT, Eugene Sidelnyk zsidelnik@gmail.com:
function foo(A & B & E $object) {
// some work
var_dump($object);
}You mean intersections? Psalm supports this notation.
IIRC we discussed intersection data types when union types were on the
table and we settled on a "take it slow" position. That said, union types
are... checks notes... oh, wow. Actually still pretty new (introduced
in 8.0).
My conservative side wants to wait and see what the community does with
unions, but if static analyzers are already providing this functionality,
then maybe the community has already made its position known.
Questions to answer in any RFC on this topic:
-
Do we support complex types combining unions with intersections?
e.g. function foo(((countable&traversable) | (stringable|jsonserializable))
$obj) { ... }
Pros: Super descriptive
Cons: Super ugly
My opinion: Maybe, but not immediately. Let simple unions/intersections
bake for a version or two. -
Do we also bring in type alliasing?
e.g.
type CountableTraversable = Countable & Traversable;
type AllTheSerializations = Stringable & JSONSerializable;
function foo(CountableTraversable | AllTheSerializations $obj) { ... }
Pros: Can make a given code base more readable once you know the types
Cons: Can make figuring out types in a new codebase harder.
My opinion: Yes. Sooner the better. -
How does this intersect (pun!) with coersion when strict_types=0 ?
Initial thoughts: Probably very poorly. -
Should we be considering other bloat^W features?
a. Exclusive Union: type SingleSerialization = Stringable ^
JSONSerializable; // XOR: Must be one, but not both
b. Blacklist: type AnythingButDOM = !DOMElement;
My opinion: Hell no. Just spitballin'.
-Sara
2020-11-07 15:12 GMT, Eugene Sidelnyk zsidelnik@gmail.com:
function foo(A & B & E $object) {
// some work
var_dump($object);
}You mean intersections? Psalm supports this notation.
IIRC we discussed intersection data types when union types were on the
table and we settled on a "take it slow" position. That said, union types
are... checks notes... oh, wow. Actually still pretty new (introduced
in 8.0).My conservative side wants to wait and see what the community does with
unions, but if static analyzers are already providing this functionality,
then maybe the community has already made its position known.
I would be very in favor of intersection types. It's not really useful for primitives, but with interfaces it becomes quite handy.
Questions to answer in any RFC on this topic:
- Do we support complex types combining unions with intersections?
e.g. function foo(((countable&traversable) | (stringable|jsonserializable))
$obj) { ... }
Pros: Super descriptive
Cons: Super ugly
My opinion: Maybe, but not immediately. Let simple unions/intersections
bake for a version or two.
I'd favor a type being exclusively unions or intersections. No mixing, with the possible exception of allowing the type to be nullable. So Foo & Bar is OK, Bar | Baz is OK, but Foo & Bar | Baz is just more complex than any reasonable person should be doing.
- Do we also bring in type alliasing?
e.g.
type CountableTraversable = Countable & Traversable;
type AllTheSerializations = Stringable & JSONSerializable;
function foo(CountableTraversable | AllTheSerializations $obj) { ... }
Pros: Can make a given code base more readable once you know the types
Cons: Can make figuring out types in a new codebase harder.
My opinion: Yes. Sooner the better.
This is a separate RFC from intersection types and should be submitted separately. That said, yes please!
- How does this intersect (pun!) with coersion when strict_types=0 ?
Initial thoughts: Probably very poorly.
I'm unclear how/why it would? Please explain?
- Should we be considering other bloat^W features?
a. Exclusive Union: type SingleSerialization = Stringable ^
JSONSerializable; // XOR: Must be one, but not both
b. Blacklist: type AnythingButDOM = !DOMElement;
My opinion: Hell no. Just spitballin'.-Sara
Hard pass. At that point, make separate methods.
--Larry Garfield
- Do we support complex types combining unions with intersections?
We can do it at any time, so we should not hurry with this.
If we think about why people would like to do such complex types -
probably it is because PHP currently doesn't support methods overloading.
Thus we'd rather introduce methods overloading than complex union
structures, but with yet that is a different topic.
- Do we also bring in type aliasing?
Think that would be great (class can define some types, which it uses, so
that client code can type-hint it):
class Foo
{
public type Collection = Countable & Traversable;
public function doThisAndThat(self::Collection $collection)
{
// ...
}
}
class Bar
{
public function delegateToFoo(Foo::Collection $collection)
{
$this->foo->doThisAndThat($collection);
}
}
But, as Larry told, it should be a different RFC.
- How does this intersect (pun!) with coercion when strict_types=0 ?
If we don't introduce complex structures (I hope), it should work the same
way independently of whether strict_types is 0 or 1.
- Should we be considering other bloat^W features?
Not really. There should be some case where such features are actually
needed.
Regards, Eugene
On Sat, Nov 7, 2020 at 9:33 AM Olle Härstedt olleharstedt@gmail.com
wrote:2020-11-07 15:12 GMT, Eugene Sidelnyk zsidelnik@gmail.com:
function foo(A & B & E $object) {
// some work
var_dump($object);
}You mean intersections? Psalm supports this notation.
IIRC we discussed intersection data types when union types were on the
table and we settled on a "take it slow" position. That said, union types
are... checks notes... oh, wow. Actually still pretty new (introduced
in 8.0).My conservative side wants to wait and see what the community does with
unions, but if static analyzers are already providing this functionality,
then maybe the community has already made its position known.Questions to answer in any RFC on this topic:
Do we support complex types combining unions with intersections?
e.g. function foo(((countable&traversable) |
(stringable|jsonserializable)) $obj) { ... }
Pros: Super descriptive
Cons: Super ugly
My opinion: Maybe, but not immediately. Let simple unions/intersections
bake for a version or two.Do we also bring in type alliasing?
e.g.
type CountableTraversable = Countable & Traversable;
type AllTheSerializations = Stringable & JSONSerializable;
function foo(CountableTraversable | AllTheSerializations $obj) { ... }
Pros: Can make a given code base more readable once you know the types
Cons: Can make figuring out types in a new codebase harder.
My opinion: Yes. Sooner the better.How does this intersect (pun!) with coersion when strict_types=0 ?
Initial thoughts: Probably very poorly.Should we be considering other bloat^W features?
a. Exclusive Union: type SingleSerialization = Stringable ^
JSONSerializable; // XOR: Must be one, but not both
b. Blacklist: type AnythingButDOM = !DOMElement;
My opinion: Hell no. Just spitballin'.-Sara
Hey Eugene,
function foo(A & B & E $object) { // some work var_dump($object); }
Fully support this for parameter, property and return types: already making
good use of intersection types since a few years.
As for when to allow them: as others have suggested in this thread, keep it
simple for now, and only allow intersection of class/interface references.
If you want to raise an RFC, special care has to be taken for the variance
in inheritance semantics.
Greets,
Marco Pivetta
As for when to allow them: as others have suggested in this thread, keep
it simple for now, and only allow intersection of class/interface
references.
Yes, I think that single intersection type should support just one class
and any/or any number of interfaces with the condition that they don't
collide with one another.
If you want to raise an RFC, special care has to be taken for the
variance in inheritance semantics.
I don't think neither that I am able to consider all possible impacts to
write the RFC nor implement this, but Levi Morrison (levim@php.net) can.
Hey Eugene,
On Sat, Nov 7, 2020 at 4:13 PM Eugene Sidelnyk zsidelnik@gmail.com
wrote:function foo(A & B & E $object) { // some work var_dump($object); }
Fully support this for parameter, property and return types: already
making good use of intersection types since a few years.As for when to allow them: as others have suggested in this thread, keep
it simple for now, and only allow intersection of class/interface
references.If you want to raise an RFC, special care has to be taken for the variance
in inheritance semantics.Greets,
Marco Pivetta
Levi will not have time for this. Who else do you suggest?
As for when to allow them: as others have suggested in this thread, keep
it simple for now, and only allow intersection of class/interface
references.Yes, I think that single intersection type should support just one class
and any/or any number of interfaces with the condition that they don't
collide with one another.If you want to raise an RFC, special care has to be taken for the
variance in inheritance semantics.I don't think neither that I am able to consider all possible impacts to
write the RFC nor implement this, but Levi Morrison (levim@php.net) can.Hey Eugene,
On Sat, Nov 7, 2020 at 4:13 PM Eugene Sidelnyk zsidelnik@gmail.com
wrote:function foo(A & B & E $object) { // some work var_dump($object); }
Fully support this for parameter, property and return types: already
making good use of intersection types since a few years.As for when to allow them: as others have suggested in this thread, keep
it simple for now, and only allow intersection of class/interface
references.If you want to raise an RFC, special care has to be taken for the
variance in inheritance semantics.Greets,
Marco Pivetta
Levi will not have time for this. Who else do you suggest?
Please do NOT prompt someone to implement a feature for you for free.
Many of us would like intersection types but it takes time to implement it.
And as a reminder most people who work on php-src do so on their free time
with no compensation whatsoever.
I recommend you read this article from Christopher Jones from Oracle about
the PHP RFC process:
https://blogs.oracle.com/opal/the-mysterious-php-rfc-process-and-how-you-can-change-the-web
Now, if you are interested in implementing it yourself there are various
resources available which we
would be happy to link you.
Best,
George P. Banyard
PS: Again, please do not top post as it is one of the guidelines of this
mailing list, see:
https://github.com/php/php-src/blob/master/docs/mailinglist-rules.md
I am wondering why don't you create some kind of donation system?
So that customers (end programmers) can vote for features by means of their
money. In russian it is known as "Голосуй рублём".
This will give the community an ability to provide feedback of what
features they like or don't.
BTW, this way people won't be able to cheat inasmuch vote is an monetary
unit
Levi will not have time for this. Who else do you suggest?
Please do NOT prompt someone to implement a feature for you for free.
Many of us would like intersection types but it takes time to implement it.
And as a reminder most people who work on php-src do so on their free time
with no compensation whatsoever.I recommend you read this article from Christopher Jones from Oracle about
the PHP RFC process:https://blogs.oracle.com/opal/the-mysterious-php-rfc-process-and-how-you-can-change-the-web
Now, if you are interested in implementing it yourself there are various
resources available which we
would be happy to link you.Best,
George P. Banyard
PS: Again, please do not top post as it is one of the guidelines of this
mailing list, see:
https://github.com/php/php-src/blob/master/docs/mailinglist-rules.md