Hello internals,
I would like to open the discussion on the RFC to add true as a type.
https://wiki.php.net/rfc/true-type
Now that null and false can be used as standalone types, I think it makes a
lot of sense to add true as a value type for the sake of completeness with
false.
It also has many use cases within internals and userland to declare proper
type signatures to functions and methods.
Best regards,
George P. Banyard
Den 2022-04-08 kl. 18:47, skrev G. P. B.:
Hello internals,
I would like to open the discussion on the RFC to add true as a type.
https://wiki.php.net/rfc/true-typeNow that null and false can be used as standalone types, I think it makes a
lot of sense to add true as a value type for the sake of completeness with
false.It also has many use cases within internals and userland to declare proper
type signatures to functions and methods.Best regards,
George P. Banyard
Finally, I have been waiting for this :) Two comments:
- Would be nice to have an example / UC that shows the value of true as
a type in the RFC. - Should one have a link to the earlier discussion about this type,
either in the RFC or in the announcement on the internals list?
Regards //Björn
Hi
Now that null and false can be used as standalone types, I think it makes a
lot of sense to add true as a value type for the sake of completeness with
false.
I agree that it would make sense to have 'true' as the counterpart of
false
for completeness, but …
It also has many use cases within internals and userland to declare proper
type signatures to functions and methods.
… seeing the examples of functions that might return true
, but won't
return false, I feel like the correct solution is not adding true
as a
standalone type, but instead making those function return something more
obvious.
-
The
sort()
family should rather be be ': void' which would make it
more obvious to static analysis that '$sorted = sort($unsorted)' is not
a correct usage. -
DiagnoseCommand::checkComposerSchema()
in composer would benefit
from having support for tagged unions, as currently both the error case
(string
) and the success case (true
) are truthy. With the current
PHP 8.1 feature set I can imagine that returning a proper bool and
putting the reason in anstring &$reason
reference parameter would
make it more obvious to use this function in anif ()
. -
JsonFile::validateSchema()
in composer should be ': void' as errors
appear to be communicated using Exceptions. -
The closure in
ComposerRepository::asyncFetchFile()
would benefit
from having support for tagged unions, but even with the current PHP 8.1
feature set I can imagine that:enum CacheStatus { case Hit; }
and then making the function mixed[]|CacheStatus
instead of
mixed[]|true
would make it more obvious what the meaning of the second
option in the union is.
Best regards
Tim Düsterhus
Hi
Now that null and false can be used as standalone types, I think it
makes a
lot of sense to add true as a value type for the sake of completeness
with
false.I agree that it would make sense to have 'true' as the counterpart of
false
for completeness, but …It also has many use cases within internals and userland to declare
proper
type signatures to functions and methods.… seeing the examples of functions that might return
true
, but won't
return false, I feel like the correct solution is not addingtrue
as a
standalone type, but instead making those function return something more
obvious.
The
sort()
family should rather be be ': void' which would make it
more obvious to static analysis that '$sorted = sort($unsorted)' is not
a correct usage.
DiagnoseCommand::checkComposerSchema()
in composer would benefit
from having support for tagged unions, as currently both the error case
(string
) and the success case (true
) are truthy. With the current
PHP 8.1 feature set I can imagine that returning a proper bool and
putting the reason in anstring &$reason
reference parameter would
make it more obvious to use this function in anif ()
.
JsonFile::validateSchema()
in composer should be ': void' as errors
appear to be communicated using Exceptions.The closure in
ComposerRepository::asyncFetchFile()
would benefit
from having support for tagged unions, but even with the current PHP 8.1
feature set I can imagine that:enum CacheStatus { case Hit; }
and then making the function
mixed[]|CacheStatus
instead of
mixed[]|true
would make it more obvious what the meaning of the second
option in the union is.Best regards
Tim Düsterhus
There are many many many more internal functions in PHP which only return
true, but only since PHP 8.0.0, and this is due to the huge amount of
E_WARNING
to ValueError/TypeError promotion which has happened.
These functions previously did return false in certain circumstances, and
although I agree that changing these to void would be the most ideal,
being able to do this communicating that these functions only return true
(which means one can ignore the return value) is the first step.
Moreover, it is even more of a BC break compared to changing something
which only returns false to void as code like:
if (always_true(...)){ ... }
would stop executing this code path.
Not adding true as a type prevents extending methods which return bool to
always return true to clearly document this within the typesystem.
Best regards,
George P. Banyard
Hi,
There are many many many more internal functions in PHP which only return
true, but only since PHP 8.0.0, and this is due to the huge amount of
E_WARNING
to ValueError/TypeError promotion which has happened.
These functions previously did return false in certain circumstances, and
although I agree that changing these to void would be the most ideal,
being able to do this communicating that these functions only return true
(which means one can ignore the return value) is the first step.
Moreover, it is even more of a BC break compared to changing something
which only returns false to void as code like:
if (always_true(...)){ ... }
would stop executing this code path.Not adding true as a type prevents extending methods which return bool to
always return true to clearly document this within the typesystem.
Then you should probably update the RFC to say that, and better examples ;)
Maybe also add an example of "refinement" during inheritance (from : bool
to : true
)?
One more thing: maybe the part about true|false
being an error (use
bool
) should be its own subsection, as that's not exactly "redundancy",
and differs from array|\Traversable
being interchangeable with iterable
.
Regards,
--
Guilliam Xavier
Hi
There are many many many more internal functions in PHP which only return
true, but only since PHP 8.0.0, and this is due to the huge amount of
E_WARNING
to ValueError/TypeError promotion which has happened.
These functions previously did return false in certain circumstances, and
I see. I think you should clarify this in the "Examples" section, that
(some of) these functions previously were an actual : bool
instead of
: true
.
although I agree that changing these to void would be the most ideal,
being able to do this communicating that these functions only return true
(which means one can ignore the return value) is the first step.
Moreover, it is even more of a BC break compared to changing something
which only returns false to void as code like:
if (always_true(...)){ ... }
would stop executing this code path.
I was not attempting to argue that the return type should be changed to
: void
(because of the obvious BC issues). Instead I believe that
probably would choose an entirely different return type if the functions
would be newly introduced.
Not adding true as a type prevents extending methods which return bool to
always return true to clearly document this within the typesystem.
This argument was also used for allowing null
/ false
as a
standalone type, because there is no good reason to allow null
/
false
in a union type, but not standalone.
For true
the story is different, as this type is an entirely new type
available to userland and by the same argument one could have literal
strings or literal integers as distinct types as well. I wouldn't object
to that per se (and there's precedent in TypeScript), but there could be
a clearer plan for the type system as a whole, instead of adding types
piecemeal.
I can see the value in having true
for completeness, though.
Best regards
Tim Düsterhus
For
true
the story is different, as this type is an entirely new type
available to userland and by the same argument one could have literal
strings or literal integers as distinct types as well. I wouldn't object
to that per se (and there's precedent in TypeScript), but there could be
a clearer plan for the type system as a whole, instead of adding types
piecemeal.
^This. The bit about making a plan, I mean. A slow erosion of what it
means to be a type might be the easier pill to swallow, but it results in
more chaos overall in the type system. I'd like to see someone (literally
anyone) take the time to sketch out a more complete picture for the type
system. We can implement it in pieces and parts, but we should have a goal
in mind for where we want to land.
Using this RFC as an example, it naturally leads into the question of value
types (which is what true
really is, a bool with a value of true), so why
can't we say this method must return the number 42 or a string containing
'pamplemousse' ? A roadmap would help us understand what those kinds of
value types (in an unbounded type like string or a large bounded type like
int) compared to the tight bounded type of bool.
And yes. Generics. We can't talk about the type system without the
subject of generics being extremely relevant. Ignoring them because it's
complicated is just kicking the can down the road.
All that having been said, sure. I don't mind adding true for completeness,
because it's fairly obvious and the scope of bool is fairly small, but I
would really encourage anyone to step up and plan out a wider reaching goal
for the type system.
-Sara
sketch out a more complete picture for the type
system. We can implement it in pieces and parts, but we should have a goal
in mind for where we want to land.
I think the type system in psalm is pretty cool. It does have fixed
literal values, but also deeply structured array types.
But:
- I don't think we'll arrive there in one leap
- I am not sure we want to arrive there, ever. Perhaps it is just
too much for native support, especially if we want repeated runtime
checks. - Runtime checks on array types seem like a nightmare.
- I am pretty confident that adding
true
won't close any doors fur
future type systems, if we already havefalse
.
Alternatively we could look at compile-time type systems like in C++
(or Java?), where we don't have to waste time on runtime checks.
The default implicit variable type could be "variant", but variables
with a declared type would behave as in C++, with a faster and slimmer
storage model.
Of course any union type that allows values other than object or null
would have to use the storage model of "variant".
Sounds like a lot of work, but if we want to dream big, it is
something to consider.
(There might be better examples than C++, I only mention it because I
spent some time with it long ago. Perhaps even Java?)
-- Andreas
For
true
the story is different, as this type is an entirely new type
available to userland and by the same argument one could have literal
strings or literal integers as distinct types as well. I wouldn't object
to that per se (and there's precedent in TypeScript), but there could be
a clearer plan for the type system as a whole, instead of adding types
piecemeal.^This. The bit about making a plan, I mean. A slow erosion of what it
means to be a type might be the easier pill to swallow, but it results in
more chaos overall in the type system. I'd like to see someone (literally
anyone) take the time to sketch out a more complete picture for the type
system. We can implement it in pieces and parts, but we should have a goal
in mind for where we want to land.Using this RFC as an example, it naturally leads into the question of value
types (which is whattrue
really is, a bool with a value of true), so why
can't we say this method must return the number 42 or a string containing
'pamplemousse' ? A roadmap would help us understand what those kinds of
value types (in an unbounded type like string or a large bounded type like
int) compared to the tight bounded type of bool.And yes. Generics. We can't talk about the type system without the
subject of generics being extremely relevant. Ignoring them because it's
complicated is just kicking the can down the road.All that having been said, sure. I don't mind adding true for completeness,
because it's fairly obvious and the scope of bool is fairly small, but I
would really encourage anyone to step up and plan out a wider reaching goal
for the type system.-Sara
Hello internals,
I've expanded on the RFC:
https://wiki.php.net/rfc/true-type
Please let me know if there are still aspects which need clarification.
I will also say that I think enums are far superior to literal types, but
only having false and not true is extremely weird to me (and in a pure type
theoretical perspective I would have preferred to not even have false).
The complexity of the implementation is also "trivial" because the PHP
engine already considers true and false to be two different ZVAL types,
whereas a complete literal type implementation is going to be way more
complex and I doubt be far from efficient.
Best regards,
George P. Banyard
Hello internals,
I will open voting on this tomorrow unless further comments.
https://wiki.php.net/rfc/true-type
Best regards,
George P. Banyard