[RFC] Add true as type

php.internals

Girgias

4 years ago
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

Unnamed Person

4 years ago
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-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 >
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

Tim Düsterhus

4 years ago
Hi On 4/8/22 18:47, G. P. B. wrote:
> 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 an `string &$reason` reference parameter would make it more obvious to use this function in an `if ()`. - `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

Girgias

4 years ago
On Sat, 9 Apr 2022 at 12:05, Tim Düsterhus <tim@bastelstu.be> wrote:
> Hi > > On 4/8/22 18:47, G. P. B. wrote: > > 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 an `string &$reason` reference parameter would > make it more obvious to use this function in an `if ()`. > - `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

Guilliam Xavier

4 years ago
Hi, On Mon, Apr 11, 2022 at 3:33 PM G. P. B. <george.banyard@gmail.com> wrote:
> > 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

Tim Düsterhus

4 years ago
Hi On 4/11/22 15:32, G. P. B. wrote:
> 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

Sara Golemon

4 years ago
On Mon, Apr 11, 2022 at 8:59 AM Tim Düsterhus <tim@bastelstu.be> wrote:
> 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

Andreas Hennings

4 years ago
> 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 have `false`. 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 On Mon, 11 Apr 2022 at 18:18, Sara Golemon <pollita@php.net> wrote:

Girgias

4 years ago
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

Girgias

4 years ago
Hello internals, I will open voting on this tomorrow unless further comments. https://wiki.php.net/rfc/true-type Best regards, George P. Banyard