Re: [PHP-DEV] Union Class Types (was Union Type (singular) straw manproposal)

  106891
September 6, 2019 07:15 mike@newclarity.net (Mike Schinkel)
Before responding to your points let me reiterate that I made the proposal as much to generate discussion on ideas that I was not seeing discussed as to see *my* proposal get selected and implemented.  So I like to think I won't be defensive about any criticism, and will be happy if the only thing that comes out of this is seeing these concepts considered that I did not think were being discussed.

> -- New magical methods that appear out of nowhere without an > interface, e.g. ::type(), ::value(), ::setValue(), ::toXZY(). if these > magical methods suddenly appear with may be varadic based on the value > of the `types` setting, this is inconsistent to the rest of PHP.
That is a really good point, and something I agonized over.ai (By your use of the term "variadic" I assume you are referring to the fact that toXxxx() functions would be defined based on the number of types listed after the types keyword?) I thought about the potential to propose a base class but that would not address the toXxxx() functions. And the same problem exists with an interface, right? I thought about the potential to propose a `typedValue()` method to which you would pass the type you want to return, but types are not first-class in PHP and are only represented in strings such as you get when called gettype(). So that would mean the method could not be typed and thus effectively eliminate the whole point of the proposal. Another issue with a base class and an interface is the desire to create a syntax that can be concise yet still leverage what already exists as much as possible as illustrated by these two examples from the proposal: function showNumber(new class{types int|float} $number) { echo $number->value(); } function showNumber2(int|float $number) { echo $number->value(); } It would be very tedious is we had to do this: function showNumber(new class extends UnionClass {types int|float} $number) { echo $number->value(); } Or worse: function showNumber(new class implements UnionInterface {types int|float; function type(){...}; function value(){...}; etc...} $number) { echo $number->value(); } So, I will turn it around. How can we address this better than I proposed? I sincerely did my best thus far, but I am sure it can be done better if only I could envision it. (One idea would be for it to automatically implement a magic "UnionTypes" interface. Which would also need to be variadic.)
> -- There is no mention of what happens if there is multiple `types` in > a definition.
I don't understand this point. Didn't my type example use int|float and then add string and \Foo\Bar? I am sure you were referring to something else, but it is not clicking for me.
> -- Why is the syntax using | as a separator where all other decls is > using a comma separated list?
Because that is the same syntax as both recent union types proposal used and also PHPDoc, for example: https://github.com/nikic/php-rfcs/blob/union-types/rfcs/0000-union-types-v2.md#proposal <https://github.com/nikic/php-rfcs/blob/union-types/rfcs/0000-union-types-v2.md#proposal> And one of the reasons I think they may have chose that syntax is because I think using a comma here would potentially result in some developer confusion if not ambiguity, and to use pipes in the function parameter list but commas after the type keyword would be inconsistent: function showNumber2(int,float $number) { echo $number->value(); } That said, I am agnostic about that syntax; I picked what seemed to be the best. When I started writing it I was planning to propose a new language feature called a union that could be declared like this: union Number { int; float; } Or like this function showNumber2(union{int;float} $number) { echo $number->value(); } But as I wrote it up I realized that what I was proposing was simply a class with some special properties. To be clear the aspect of the proposal that is most fundamental is the auto-creation of the union class instance when a value is passed as a parameter or assigned to a property declare for that union class and the "variadic" methods that allow accessing the values in a type safe way,
> -- Nitpick The "types" decl doesn't use an ending semicolon in any of > your examples > -- Nitpick: Your examples in the "Accepting params into a union > instance" section uses $this in a procedural function
Doh! Copy paste error and my normal dependence on PhpStorm to ensure my syntax is always correct (but I can't have PhpStorm correct my proposed future syntax!) Anyway, fixed. And thanks for catching.
> -- In the "Named Union equivalence to anonymous union" section I fail > to see how Building2 can magically accept Building, this is based on > properties and there is there is no mention of the ability to have (or > not to have) multiple named unions as property types.
Well, would you accept "magic" as a valid answer? :-D Seriously though, I envision that PHP would need to keep a types token for union classes that could be compared for type equivalence. PHP would need to take the list of types and although I assume it would be better do use a more compact internal form I'll use a string for discussion. It would sort the types and convert to a string like "int|float" and/or "int|float|string" and then do the same for the function. It would then compare them for equivalence to determine Effectively what I am proposing here is a form of structural typing vs. nominal typing, which can be done easily since the list of types is https://en.wikipedia.org/wiki/Structural_type_system <https://en.wikipedia.org/wiki/Structural_type_system> https://en.wikipedia.org/wiki/Nominal_type_system <https://en.wikipedia.org/wiki/Nominal_type_system> https://medium.com/@thejameskyle/type-systems-structural-vs-nominal-typing-explained-56511dd969f4 <https://medium.com/@thejameskyle/type-systems-structural-vs-nominal-typing-explained-56511dd969f4> BTW, I also would like to later to propose PHP consider supporting structural typing because there are so many things we could do with PHP and type hinting if we had this that we cannot do today, such as pressure that every class with a __ToString() method implements a hypothetical standardized Stringable() interface. It would also allow us to use interfaces with PHP libraries where the original author did not explicitly declare that his classes implemented the interface you happen to need.
> -- Is this designed to be only meant for mutability (You are > publically exposing setValue())?
Sorry, I do not understand the context of this question.
> -- What happens if the class is extended?
I just updated the proposal to provide an example, but I was not able to discover any edge cases that would have it behave any differently than extended classes currently behave. Was there any edge cases you were thinking about, or just noting that I did not have a section covering extension?
> -- Why is it desired to implement a namespaced class instance return? > If you are working on the object, you should already have access to > this information it provides, no?
That is a good question. It might be an edge case I did not consider, although I'm still not sure. What should happen if we wanted this union? namespace Autos class Mercedes { types German\Mercedes | Austrian\Mercedes; }
> -- Why is ::types() apart of the union instead of leaving that to > reflection? > No other part of PHP exposes such as a method over > procedural functions (like get_object_vars()).
Because using Reflection can requires a mental translation at times. At least for me. So since I like the convenience of it and as it was my proposal so I thought I'd slide it in. :-D That said, totally does not matter to the proposal. As I envisioned it, this was a straw man proposal, intended to be torn apart, and then hopefully reassembled into something better. Does this address all your concerns, at least well enough to bring up additional concerns? Whatever the case, I appreciate the many questions, even if it was in the morning. :-) -Mike