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