Dear Internals,
I am pleased to announce that the return type RFC is now open for
voting1. Note that the implementation needs a bit of cleaning up
before merging should the RFC be accepted; Dmitry has already
volunteered to help with that, but more eyes are welcome.
A couple of things have changed in reflection2 since the last
iteration, but is otherwise the same.
The implementation is slightly out of date with the RFC, but soon it
will be updated to match.
Dear Internals,
I am pleased to announce that the return type RFC is now open for
voting1. Note that the implementation needs a bit of cleaning up
before merging should the RFC be accepted; Dmitry has already
volunteered to help with that, but more eyes are welcome.A couple of things have changed in reflection2 since the last
iteration, but is otherwise the same.The implementation is slightly out of date with the RFC, but soon it
will be updated to match.
I failed to note that voting will be open until the evening of
November 14th, UTC-7.
Le 04/11/2014 03:01, Levi Morrison a écrit :
Dear Internals,
I am pleased to announce that the return type RFC is now open for
voting1. Note that the implementation needs a bit of cleaning up
before merging should the RFC be accepted; Dmitry has already
volunteered to help with that, but more eyes are welcome.A couple of things have changed in reflection2 since the last
iteration, but is otherwise the same.The implementation is slightly out of date with the RFC, but soon it
will be updated to match.Excellent RFC, thank you. However, there is no mention about using
static
,self
orparent
as a type (it is possible for an argument).
Something like:
class Singleton {
public function getInstance ( $x, $y): static { … }
}
Maybe I miss it in the discussion?
Thoughts?
Regards.
--
Ivan Enderlin
Developer of Hoa
http://hoa-project.net/
PhD. at DISC/Femto-ST (Vesontio) and INRIA (Cassis)
http://disc.univ-fcomte.fr/ and http://www.inria.fr/
Member of HTML and WebApps Working Group of W3C
http://w3.org/
Ivan Enderlin @ Hoa wrote:
Excellent RFC, thank you. However, there is no mention about using
static
,self
orparent
as a type (it is possible for an argument).
Something like:class Singleton { public function getInstance ( $x, $y): static { … } }
Maybe I miss it in the discussion?
Thoughts?
The possible usage of self and parent is already documented:
https://wiki.php.net/rfc/returntypehinting#differences_from_past_rfcs.
Regarding static, see http://news.php.net/php.internals/78116.
--
Christoph M. Becker
Le 04/11/2014 09:37, Christoph Becker a écrit :
Ivan Enderlin @ Hoa wrote:
Excellent RFC, thank you. However, there is no mention about using
static
,self
orparent
as a type (it is possible for an argument).
Something like:class Singleton { public function getInstance ( $x, $y): static { … } }
Maybe I miss it in the discussion?
Thoughts?
The possible usage of self and parent is already documented:
https://wiki.php.net/rfc/returntypehinting#differences_from_past_rfcs.Regarding static, see http://news.php.net/php.internals/78116.
Thanks :-).
--
Ivan Enderlin
Developer of Hoa
http://hoa-project.net/
PhD. at DISC/Femto-ST (Vesontio) and INRIA (Cassis)
http://disc.univ-fcomte.fr/ and http://www.inria.fr/
Member of HTML and WebApps Working Group of W3C
http://w3.org/
Hi Levi,
The patch is here https://gist.github.com/dstogov/8deb8b17e41c1a5abf88
I improved memory consumption and unified return type-hinting error
behavior with existing argument type-hinting.
The main semantic must be unchanged.
I also removed part of Reflection changes. I think we should remove even
more and later introduce similar APIs for both argument and return
type-hinting at once.
Working on the patch I found few problems.
-
Return type-hinting for generators in existing state is useless. We may
use it for checking "yield" value instead of "returned" or just disable it
for now. -
"Covariant" return type check is really problematic. It delays class
binding to run-time, and requires all classes, used in hints, to be loaded.
I would prefer to simplify this by using "Invariant" return types (similar
to arguments) and checking just class names (without their loading).
Thanks. Dmitry.
On Tue, Nov 4, 2014 at 5:01 AM, Levi Morrison morrison.levi@gmail.com
wrote:
Dear Internals,
I am pleased to announce that the return type RFC is now open for
voting1. Note that the implementation needs a bit of cleaning up
before merging should the RFC be accepted; Dmitry has already
volunteered to help with that, but more eyes are welcome.A couple of things have changed in reflection2 since the last
iteration, but is otherwise the same.The implementation is slightly out of date with the RFC, but soon it
will be updated to match.
Hi Levi,
The patch is here https://gist.github.com/dstogov/8deb8b17e41c1a5abf88
I improved memory consumption and unified return type-hinting error
behavior with existing argument type-hinting.
The main semantic must be unchanged.
This sounds good.
I also removed part of Reflection changes. I think we should remove even
more and later introduce similar APIs for both argument and return
type-hinting at once.
I'd rather not go through 3 weeks of internals to get in ReflectionType for parameters. I'd imagine adding ->getReflectionType for parameters would be fairly uncontroversial, can we just do that now?
Working on the patch I found few problems.
- Return type-hinting for generators in existing state is useless. We may
use it for checking "yield" value instead of "returned" or just disable it
for now.
I don't think it's useless. You can require a function to be a generator. Is that bad?
If we added generics in future, we could then type the yielded type, e.g. Generator<int> maybe?
- "Covariant" return type check is really problematic. It delays class
binding to run-time, and requires all classes, used in hints, to be loaded.
The former sounds like a problem, but doesn't inheritance require these classes to be loaded anyway?
Do we always load the class in the hint? We could perhaps only do it for inheritance checks?
I would prefer to simplify this by using "Invariant" return types (similar
to arguments) and checking just class names (without their loading).
This is problematic, it'd stop classes from changing return types to subclasses in inheritance, which would make them less useful.
Andrea Faulds
http://ajf.me/
Hi!
Do we always load the class in the hint? We could perhaps only do it
for inheritance checks?
No, classes are not loaded for type checks, since it would be pointless
- if the class is not loaded, you could not have a value of that type,
so if the class is not present, the answer is "no".
--
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
Hi!
Do we always load the class in the hint? We could perhaps only do it
for inheritance checks?No, classes are not loaded for type checks, since it would be pointless
- if the class is not loaded, you could not have a value of that type,
so if the class is not present, the answer is "no".
I'm aware master doesn't. I'm asking about the patch. :/
--
Andrea Faulds
http://ajf.me/
On Thu, Nov 6, 2014 at 12:05 AM, Stas Malyshev smalyshev@sugarcrm.com
wrote:
Hi!
Do we always load the class in the hint? We could perhaps only do it
for inheritance checks?No, classes are not loaded for type checks, since it would be pointless
- if the class is not loaded, you could not have a value of that type,
so if the class is not present, the answer is "no".
It's not true anymore, with this proposal.
Thanks. Dmitry.
--
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
On Thu, Nov 6, 2014 at 12:05 AM, Stas Malyshev smalyshev@sugarcrm.com
wrote:Hi!
Do we always load the class in the hint? We could perhaps only do it
for inheritance checks?No, classes are not loaded for type checks, since it would be pointless
- if the class is not loaded, you could not have a value of that type,
so if the class is not present, the answer is "no".It's not true anymore, with this proposal.
Thus my suggestion that we only load for the inheritance checks (and only if the type differed). We don't need to normally.
--
Andrea Faulds
http://ajf.me/
Hi!
No, classes are not loaded for type checks, since it would be pointless - if the class is not loaded, you could not have a value of that type, so if the class is not present, the answer is "no".
It's not true anymore, with this proposal.
This is not good. The base premise of type checks always was if you
don't use them, they are basically free - you don't load the classes,
you don't do any work, until you actually need them, and by then your
class is supposed to be already loaded, so again it's not costly. But if
just declaring a type could trigger loading of code, this may
significantly increase the footprint and loading time for classes that
have many options but only use some of them at the time.
Also, it is kind of weird that arguments require exact match but return
types do not. Not that we care for consistency anymore...
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
I would also prefer to use the same return type hinting compatibility rules
as for argument type-hinting.
May be it's less smart, but more practical.
http://en.wikipedia.org/wiki/Covariance_and_contravariance_%28computer_science%29
Thanks. Dmitry.
On Thu, Nov 6, 2014 at 1:15 AM, Stas Malyshev smalyshev@sugarcrm.com
wrote:
Hi!
No, classes are not loaded for type checks, since it would be
pointless
- if the class is not loaded, you could not have a value of that
type,
so if the class is not present, the answer is "no".
It's not true anymore, with this proposal.
This is not good. The base premise of type checks always was if you
don't use them, they are basically free - you don't load the classes,
you don't do any work, until you actually need them, and by then your
class is supposed to be already loaded, so again it's not costly. But if
just declaring a type could trigger loading of code, this may
significantly increase the footprint and loading time for classes that
have many options but only use some of them at the time.
Also, it is kind of weird that arguments require exact match but return
types do not. Not that we care for consistency anymore...Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
Hi!
No, classes are not loaded for type checks, since it would be pointless
- if the class is not loaded, you could not have a value of that type,
so if the class is not present, the answer is "no".It's not true anymore, with this proposal.
This is not good. The base premise of type checks always was if you
don't use them, they are basically free - you don't load the classes,
you don't do any work, until you actually need them, and by then your
class is supposed to be already loaded, so again it's not costly. But if
just declaring a type could trigger loading of code, this may
significantly increase the footprint and loading time for classes that
have many options but only use some of them at the time.
It shouldn’t need to load any code normally, it’s only if an inheriting class changes the type.
Also, it is kind of weird that arguments require exact match but return
types do not. Not that we care for consistency anymore…
Yeah, we should probably have arguments be contravariant or covariant.
I was going to argue that covariance is important, but now that I think about it, the most important case is just self. If I can have Foo::foo() return a Foo and Bar::foo() return a Bar, with Bar inheriting from Foo, and this not breaking the invariant type check, I’m happy.
--
Andrea Faulds
http://ajf.me/
Also, it is kind of weird that arguments require exact match but return
types do not. Not that we care for consistency anymore…Yeah, we should probably have arguments be contravariant or covariant.
I was going to argue that covariance is important, but now that I think about it, the most important case is just self. If I can have Foo::foo() return a Foo and Bar::foo() return a Bar, with Bar inheriting from Foo, and this not breaking the invariant type check, I’m happy.
What I meant there wasn’t self
, but actually static
, I think, which sadly this RFC doesn’t provide. I think that’d be a very useful feature. If we can’t get covariant returns and must go for invariants, I think we’d have to have static
supported.
I note that Hack also has invariant parameters and covariant return types. There’s probably some good reasoning behind that, I think it’d be worth asking some HHVM people about why that decision was taken, they might provide some useful insight.
Andrea Faulds
http://ajf.me/
To demonstrate the value of covariance and why static
alone is not
sufficient, here is a small example:
interface Enumerable extends \IteratorAggregate {
function getIterator(): Enumerator;
}
class Vector implements Enumerable, \ArrayAccess, \Countable {
function getIterator(): VectorEnumerator { /* … */ }
}
class VectorEnumerator implements Enumerator, \Countable {
/* … */
}
This shows why covariance is important for two reasons:
First, it shows that static isn't sufficient. The VectorEnumerator is
not the calling class, so self and static are not applicable.
Second, without covariance you could only declare a return type of
Enumerator for Vector::getIterator(); a calling class couldn't rely on
the properties of a VectorEnumerator that are unique to it, such as
\Countable.
It's clear, that covariant types are more smart, but not supporting them,
won't prevent access to more specific type properties and methods.
We are not C++ or Java, and we don't need to cast objects to more specific
types.
On the other hand covariance requires all return types to be defined before
class binding.
It may be a serious new problem. For example you won't be able to compile
the following code at all?
<?php
class A {
function foo(): C {}
}
class B extends A {
function foo(): C {}
}
class C extends B {
function foo(): C {}
}
?>
The similar code with argument type hinting works fine.
It's just a first example I could imagine, I believe, we will get more...
Thanks. Dmitry.
On Thu, Nov 6, 2014 at 5:01 AM, Levi Morrison morrison.levi@gmail.com
wrote:
To demonstrate the value of covariance and why
static
alone is not
sufficient, here is a small example:interface Enumerable extends \IteratorAggregate {
function getIterator(): Enumerator;
}class Vector implements Enumerable, \ArrayAccess, \Countable {
function getIterator(): VectorEnumerator { /* … */ }
}class VectorEnumerator implements Enumerator, \Countable {
/* … */
}This shows why covariance is important for two reasons:
First, it shows that static isn't sufficient. The VectorEnumerator is
not the calling class, so self and static are not applicable.
Second, without covariance you could only declare a return type of
Enumerator for Vector::getIterator(); a calling class couldn't rely on
the properties of a VectorEnumerator that are unique to it, such as
\Countable.
It's clear, that covariant types are more smart, but not supporting them,
won't prevent access to more specific type properties and methods.
We are not C++ or Java, and we don't need to cast objects to more specific
types.On the other hand covariance requires all return types to be defined before
class binding.
It may be a serious new problem. For example you won't be able to compile
the following code at all?<?php
class A {
function foo(): C {}
}
class B extends A {
function foo(): C {}
}
class C extends B {
function foo(): C {}
}
?>
I think I have figured out away to do the type checks that would allow
this and current checks to work; I'll report back after some trial and
testing.
It may be a serious new problem. For example you won't be able to compile
the following code at all?<?php
class A {
function foo(): C {}
}
class B extends A {
function foo(): C {}
}
class C extends B {
function foo(): C {}
}
?>The similar code with argument type hinting works fine.
It's just a first example I could imagine, I believe, we will get more...
I can't see any reason that example wouldn't work. The types didn't change, so there's no class loading needed for the covariance check.
--
Andrea Faulds
http://ajf.me/
Use A or B for return type in B::foo(). It'll lead to compile error anyway
(Class C is not defined).
It's not possible to compile this by design.
Thanks. Dmitry.
It may be a serious new problem. For example you won't be able to compile
the following code at all?<?php
class A {
function foo(): C {}
}
class B extends A {
function foo(): C {}
}
class C extends B {
function foo(): C {}
}
?>The similar code with argument type hinting works fine.
It's just a first example I could imagine, I believe, we will get more...I can't see any reason that example wouldn't work. The types didn't
change, so there's no class loading needed for the covariance check.--
Andrea Faulds
http://ajf.me/
Use A or B for return type in B::foo(). It'll lead to compile error anyway (Class C is not defined).
It's not possible to compile this by design.
Ok, let’s try this:
<?php
class A {
function foo(): C {}
}
class B extends A {
function foo(): B {}
}
class C extends B {
function foo(): C {}
}
?>
I don’t think this can’t be compiled. When you get to B, you know that A doesn’t extend anything, and B doesn’t extend C, so C can’t possibly be a superclass of B, and it would fail, right?
--
Andrea Faulds
http://ajf.me/
It fails because class C is not known at the point when we check if
A::foo() is compatible with B::foo().
The relation between C and B doesn't really matter in this case (I may
provide another example with relation that must be supported).
Thanks. Dmitry.
Use A or B for return type in B::foo(). It'll lead to compile error
anyway (Class C is not defined).
It's not possible to compile this by design.Ok, let’s try this:
<?php
class A {
function foo(): C {}
}
class B extends A {
function foo(): B {}
}
class C extends B {
function foo(): C {}
}
?>I don’t think this can’t be compiled. When you get to B, you know that A
doesn’t extend anything, and B doesn’t extend C, so C can’t possibly be a
superclass of B, and it would fail, right?--
Andrea Faulds
http://ajf.me/