Hello internals,
I'm proposing a new RFC to make 'null' usable as a standalone type.
RFC: https://wiki.php.net/rfc/null-standalone-type
GitHub PR: https://github.com/php/php-src/pull/7546
Best regards,
George P. Banyard
Hello internals,
I'm proposing a new RFC to make 'null' usable as a standalone type.
RFC: https://wiki.php.net/rfc/null-standalone-type
GitHub PR: https://github.com/php/php-src/pull/7546Best regards,
George P. Banyard
I don't see the word void
in the RFC. I think there ought to be
something said about how naked null
is different or not different
than void
.
On Mon, Oct 4, 2021 at 5:33 AM Levi Morrison via internals <
internals@lists.php.net> wrote:
Hello internals,
I'm proposing a new RFC to make 'null' usable as a standalone type.
RFC: https://wiki.php.net/rfc/null-standalone-type
GitHub PR: https://github.com/php/php-src/pull/7546Best regards,
George P. Banyard
I don't see the word
void
in the RFC. I think there ought to be
something said about how nakednull
is different or not different
thanvoid
.
Right. To quote the original union types RFC, this was the motivation for
the current limitation:
The null type is only allowed as part of a union, and can not be used as
a standalone type. Allowing it as a standalone type would make both
function foo(): void and function foo(): null legal function signatures,
with similar but not identical semantics. This would negatively impact
teachability for an unclear benefit.
I'm not opposed to making null usable as a standalone type though. I think
the fact that a "void" function must use "return;" instead of "return
null;" and a "null" function conversely must use "return null;" instead of
"return;" will probably be sufficient disambiguation.
If we make this change, I would however suggest to also support "false" as
a standalone type. I think this change primarily has benefits from a
typesystem completeness perspective rather than a strong practical need.
From that angle, it would be nice if all types that are usable in a union
are also usable as standalone types, rather than shifting the special case
from null to false.
Regards,
Nikita
Le lundi 4 octobre 2021, 10:09:12 CEST Nikita Popov a écrit :
If we make this change, I would however suggest to also support "false" as
a standalone type. I think this change primarily has benefits from a
typesystem completeness perspective rather than a strong practical need.
From that angle, it would be nice if all types that are usable in a union
are also usable as standalone types, rather than shifting the special case
from null to false.
It feels weird/wrong to slowly add values in the type system like this, rather than directly supporting static values as type hints.
Why would function a(): null|false {} be legal but function b(): null|0 would not?
This is inconsistent to me. And adding null, then false, then true for the sake of completeness feels like avoiding to treat the static value as type hint subject.
Côme
Le lundi 4 octobre 2021, 10:09:12 CEST Nikita Popov a écrit :
If we make this change, I would however suggest to also support "false" as
a standalone type. I think this change primarily has benefits from a
typesystem completeness perspective rather than a strong practical need.
From that angle, it would be nice if all types that are usable in a union
are also usable as standalone types, rather than shifting the special case
from null to false.It feels weird/wrong to slowly add values in the type system like this, rather than directly supporting static values as type hints.
Why would function a(): null|false {} be legal but function b(): null|0 would not?
This is inconsistent to me. And adding null, then false, then true for the sake of completeness feels like avoiding to treat the static value as type hint subject.
Côme
--
To unsubscribe, visit: https://www.php.net/unsub.php
Null is both a type and a value. It's odd that we don't support null
as a standalone type, because it's the only case I can think of where
we have a value without a type in the type system. You could possibly
argue the same about resource
, but that's a legacy type we are
working on removing (and special thanks to everyone who has
participated).
Integers are not the same. If you want to support integer literals and
probably all forms of literals as types, I suggest that as a separate
RFC. I really don't think they are the same.
Le lundi 4 octobre 2021, 10:09:12 CEST Nikita Popov a écrit :
If we make this change, I would however suggest to also support "false"
as
a standalone type. I think this change primarily has benefits from a
typesystem completeness perspective rather than a strong practical need.
From that angle, it would be nice if all types that are usable in a union
are also usable as standalone types, rather than shifting the special
case
from null to false.It feels weird/wrong to slowly add values in the type system like this,
rather than directly supporting static values as type hints.Why would function a(): null|false {} be legal but function b(): null|0
would not?This is inconsistent to me. And adding null, then false, then true for the
sake of completeness feels like avoiding to treat the static value as type
hint subject.
Both null and false are already part of the type system. They're not being
added, neither by the RFC in question, nor by my quoted suggestion. This
discussion is only about relaxing restrictions on standalone types.
So to answer your question: "null|false" would be legal because
"string|false" already is. "null|0" would be illegal because there is no
such thing as a "0" type (in our current type system).
Regards,
Nikita
Le lundi 4 octobre 2021, 10:09:12 CEST Nikita Popov a écrit :
If we make this change, I would however suggest to also support "false"
as
a standalone type. I think this change primarily has benefits from a
typesystem completeness perspective rather than a strong practical
need.
From that angle, it would be nice if all types that are usable in a
union
are also usable as standalone types, rather than shifting the special
case
from null to false.It feels weird/wrong to slowly add values in the type system like this,
rather than directly supporting static values as type hints.Why would function a(): null|false {} be legal but function b(): null|0
would not?This is inconsistent to me. And adding null, then false, then true for
the
sake of completeness feels like avoiding to treat the static value as
type
hint subject.Both null and false are already part of the type system. They're not being
added, neither by the RFC in question, nor by my quoted suggestion. This
discussion is only about relaxing restrictions on standalone types.
I always thought false was part of the type system just to accommodate the
legacy of internal functions which can return a (non-boolean) value or
false. I mean, I've never written code that's type hinted something|false
as a return type, to me a function/method return should either be type
hinted bool or not. Even with union types, if I was writing something|bool
there might be conceivable occasions it's justified, but I'd at least be
asking myself if it could be a design smell in whatever I'm building. I
guess I'm saying I've always considered the fact you can do this with
false more a legacy of necessity than a feature which should be built on.
Null is distinctly a type as well as a value so I can see the justification
for the RFC; it seems harder to make that argument for false, beyond saying
"well in PHP, it just is"...but...is that a good thing?
So to answer your question: "null|false" would be legal because
"string|false" already is. "null|0" would be illegal because there is no
such thing as a "0" type (in our current type system).
Regards,
Nikita
Why would function a(): null|false {} be legal but function b(): null|0
would not?This is inconsistent to me. And adding null, then false, then true for the
sake of completeness feels like avoiding to treat the static value as type
hint subject.
I'm not opposed to having values that aren't objects. Feels like a
shorthand notation of enums, or the subset thereof.
function `getType()`: 'dropdown'|'textfield';
function getExitCode(): 0|1|255;
Hello internals,
I'm proposing a new RFC to make 'null' usable as a standalone type.
Regarding the RFC's proposed disallowing of ?null
, is that really needed?
Obviously it doesn't make sense for a developer to write that, but I could see that a code generator would have add special-case logic to avoid outputting ?
with the type null
.
Does it hurt anything if it is allowed?
-Mike
Hello internals,
I'm proposing a new RFC to make 'null' usable as a standalone type.
RFC: https://wiki.php.net/rfc/null-standalone-type
GitHub PR: https://github.com/php/php-src/pull/7546Best regards,
George P. Banyard
Hey George, thank you for driving the effort forward.
This looks good to me and I think having null as a return type makes it a
bit more clear.
I think the difference between a function returning void vs null will be
clear enough.
But there is one more small elephant in the RFC that I believe should be
discussed.
null|false type will not be a nullable named type but it will be an union
between two named types.
It's not totally unexpected. All types that are combined with false are a
union type so far.
But also, related to null, it will be the first case that will be different.
So far, all types that are combined with null are not necessarily union but
their other type that has an allowsNull() that returns true.
One could argue that we can also have it as a ReflectionNamedType with
getName() = 'false' and allowsNull() = true.
I feel that the preferred solution will push more towards the general
desire to represent the nullable types notations more and more like an
union.
I can see how what was initially proposed in
https://wiki.php.net/rfc/nullable_intersection_types for (X&Y)|null
might end up being UnionType(IntersectionType(NamedType(X), NamedType(Y)),
NamedType(null))
instead of the originally proposed IntersectionType(NamedType(X),
NamedType(Y) with allowsNull() = true.
I mean, that's not necessarily a bad thing in my opinion. But maybe it's
good to discuss the future plans as well.
For any new nullable construct should we use a ReflectionUnionType with
ReflectionNamedType for null and not use the allowsNull method?
Should we have a plan to convert current nullable constructs to a
ReflectionUnionType and eventually drop the allowsNull method in PHP 9.0?
On the other hand, while we have the allowsNull method maybe we can keep
the pattern and not have a BC break and use it everywhere.
With an union, you need to iterate over all elements in the union and check
that one is a named reflection for null.
Is there something we cannot achieve if we do it like this?
I don't have a strong preference for either. But I think it would be good
to discuss it.
While writing this, I realize that the RFC should probably specify in the
Reflection section also the simple use case, null, not just the null|false
combination.
I assumed it would be a ReflectionNamedType for null but I think that it
should be clearly specified along with what the getName method will return.
Also, what will the allowsNull method return? If false, should the
recommended pattern for checking if null is allowed be
($reflectionType->allowsNull() || $reflectionType->getName() === 'null')
Or maybe the name should be 'NULL', to match the result of gettype(null)?
If not, maybe we can mention the difference to the gettype function.
Regards,
Alex
On Mon, 4 Oct 2021 at 04:33, Levi Morrison levi.morrison@datadoghq.com
wrote:
I don't see the word
void
in the RFC. I think there ought to be
something said about how nakednull
is different or not different
thanvoid
.
Added a section which attempts to explain the difference between both.
If we make this change, I would however suggest to also support "false" as
a standalone type. I think this change primarily has benefits from a
typesystem completeness perspective rather than a strong practical need.
From that angle, it would be nice if all types that are usable in a union
are also usable as standalone types, rather than shifting the special case
from null to false.
I'm not against adding false as a standalone type, but I haven't amended
the RFC just yet as it would require some major rewording and I want to be
sure most people are on board with this change.
Regarding the RFC's proposed disallowing of
?null
, is that really needed?
Yes, this is in line with PHP's current type redundancy checks.
One cannot write ?mixed, nor int|int, nor iterable|Traversable, as the
types are redundant.
On Tue, 5 Oct 2021 at 23:58, Alexandru Pătrănescu drealecs@gmail.com
wrote:
But there is one more small elephant in the RFC that I believe should be
discussed.
null|false type will not be a nullable named type but it will be an union
between two named types.It's not totally unexpected. All types that are combined with false are a
union type so far.But also, related to null, it will be the first case that will be
different.
So far, all types that are combined with null are not necessarily union
but their other type that has an allowsNull() that returns true.One could argue that we can also have it as a ReflectionNamedType with
getName() = 'false' and allowsNull() = true.I feel that the preferred solution will push more towards the general
desire to represent the nullable types notations more and more like an
union.
I can see how what was initially proposed in
https://wiki.php.net/rfc/nullable_intersection_types for (X&Y)|null
might end up being UnionType(IntersectionType(NamedType(X), NamedType(Y)),
NamedType(null))
instead of the originally proposed IntersectionType(NamedType(X),
NamedType(Y) with allowsNull() = true.I mean, that's not necessarily a bad thing in my opinion. But maybe it's
good to discuss the future plans as well.
For any new nullable construct should we use a ReflectionUnionType with
ReflectionNamedType for null and not use the allowsNull method?
Should we have a plan to convert current nullable constructs to a
ReflectionUnionType and eventually drop the allowsNull method in PHP 9.0?
From my understanding and the comments in the source code, and Nikita might
want to clarify, the only reason why it still returns a NamedType is for
BC, to allow tools that worked on PHP 7 to still run on PHP 8 even if
nothing else changed.
As Reflection based tooling gets updated to deal with the additions to the
type system I expect that we will change the representation of ?T to a
ReflectionUnionType, as to maintain the old behaviour we do things that
could be removed and simplified by using the more standard representation.
On the other hand, while we have the allowsNull method maybe we can keep
the pattern and not have a BC break and use it everywhere.
With an union, you need to iterate over all elements in the union and
check that one is a named reflection for null.
Is there something we cannot achieve if we do it like this?
This is incorrect: https://3v4l.org/P9U4u
There is no intention to change this behaviour in this RFC.
The slightly amended RFC can be again found here:
https://wiki.php.net/rfc/null-standalone-type
Best regards,
George P. Banyard
On Tue, 5 Oct 2021 at 23:58, Alexandru Pătrănescu drealecs@gmail.com
wrote:But there is one more small elephant in the RFC that I believe should be
discussed.
null|false type will not be a nullable named type but it will be an union
between two named types.It's not totally unexpected. All types that are combined with false are a
union type so far.But also, related to null, it will be the first case that will be
different.
So far, all types that are combined with null are not necessarily union
but their other type that has an allowsNull() that returns true.One could argue that we can also have it as a ReflectionNamedType with
getName() = 'false' and allowsNull() = true.I feel that the preferred solution will push more towards the general
desire to represent the nullable types notations more and more like an
union.
I can see how what was initially proposed in
https://wiki.php.net/rfc/nullable_intersection_types for (X&Y)|null
might end up being UnionType(IntersectionType(NamedType(X),
NamedType(Y)),
NamedType(null))
instead of the originally proposed IntersectionType(NamedType(X),
NamedType(Y) with allowsNull() = true.I mean, that's not necessarily a bad thing in my opinion. But maybe it's
good to discuss the future plans as well.
For any new nullable construct should we use a ReflectionUnionType with
ReflectionNamedType for null and not use the allowsNull method?
Should we have a plan to convert current nullable constructs to a
ReflectionUnionType and eventually drop the allowsNull method in PHP 9.0?From my understanding and the comments in the source code, and Nikita might
want to clarify, the only reason why it still returns a NamedType is for
BC, to allow tools that worked on PHP 7 to still run on PHP 8 even if
nothing else changed.
As Reflection based tooling gets updated to deal with the additions to the
type system I expect that we will change the representation of ?T to a
ReflectionUnionType, as to maintain the old behaviour we do things that
could be removed and simplified by using the more standard representation.
Thanks for sharing this.
In this case, using a ReflectionUnionType sounds perfectly in line with the
plans for the future.
Related to my mention about deprecation and dropping of allowsNull, I guess
that is not really needed.
I can see how we could add along with the current public function
allowsNull(): bool
a new function like public function allows(mixed $value): bool
and keeping them both in the end could be fine.
But this is a topic for some other RFC, not for this.
On the other hand, while we have the allowsNull method maybe we can keep
the pattern and not have a BC break and use it everywhere.
With an union, you need to iterate over all elements in the union and
check that one is a named reflection for null.
Is there something we cannot achieve if we do it like this?This is incorrect: https://3v4l.org/P9U4u
There is no intention to change this behaviour in this RFC.
Thank you for the correction.
allowsNull() can be used on the ReflectionUnionType directly, of course.
I guess I was trying to find a disadvantage for it but failed.
The slightly amended RFC can be again found here:
https://wiki.php.net/rfc/null-standalone-typeBest regards,
George P. Banyard
Regards,
Alex