Re: Union Class Types (was Union Type (singular) straw man proposal)
| From: | Stephen Reay | Date: | Fri, 06 Sep 2019 08:20:47 +0000 |
| Subject: | Re: Union Class Types (was Union Type (singular) straw man proposal) | ||
| References: | 1 2 3 4 5 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-106892@lists.php.net to get a copy of this message | ||
> On 6 Sep 2019, at 14:37, Mike Schinkel <mike@newclarity.net> wrote:
>
> Hi Stephen,
>
> Thank you for taking the time to comment.
>
>> It seems like you’re trying to allow for type conversions in a predictable manner,
>
> Correct.
>
>> but in a very different way than php already does that with built in types and interfaces
>
> I proposed the best approach I could envision given the constraints of the scenario.
>
> I elaborated in my first comment in my reply to Kalle; can you look at that reply rather than
> have me repeat it?
>
> OTOH, it would be wonderful it you could envision an approach that could use types and/or
> interfaces and still have an approaching syntax when using unions in an anonymous context when
> declaring parameters to a function or method.
>
>
>> (__toString, the proposed __toArray, plus the various (de)serialiser options)
>
> Unless I misunderstand, __toString() and __toArray() do not provide type safety at the call
> site without casting.
>
> And since you cannot cast an object type in PHP — e.g. (Number)$myobject — it seems magic
> methods are not suitable for task here?
>
> Or can you envision a different alternative?
>
>
>> Your proposal seems to imply some kind of automatic method generation by the engine itself
>> (or the examples are all missing that boilerplate??) which is very non obvious to me and I think
>> would be to others too.
>
> Hmm. I was thinking of it being a lot like ArrayObject, Exception, Closure, Generator, in
> that you get methods built-in.
>
> I wonder if the lack of obviousness would simply require a one-time learning, or if it would be
> problematic for people on an ongoing basis?
>
> Digressing, as I said in other messages I proposed this as much as a discussion starter as
> anything. So I am excited to discuss any alternate approach others might suggest.
>
>> From my perspective a more obvious solution for this type of thing would be a set of
>> interfaces to define that a class can be safely cast to another type when used with typed
>> properties/arguments/returns.
>
> How would interfaces work in this context and for this use-case?
>
> I tried to leverage interfaces while writing the proposal as I know many people prefer
> enhancements be packaged as interfaces, but I could not envision how they could be applied to meet
> the goals here.
>
> And to reiterated my proposals goals they were to establish a concise syntax that leverages
> existing language features for better type safety when multiple types can correctly be passed as
> parameters and/or assigned to properties.
>
>
>> (or magic methods to match __toString but I know they’re less preferred by some these
>> days)
>
> Is it possible to get type safety from using __toString() in a manner as I am struggling to
> envision one?
>
>> tthat a class can be safely cast to another type when used with typed
>> properties/arguments/returns.
>
> What about for types where there is no syntax for casting? Such as when one ones to union
> instances of a class?
>
> Anxious to hear your additional thoughts, if you have time.
>
> But either way, I very much appreciate the time you've taken to comment.
>
> -Mike
>
>
>> On Sep 6, 2019, at 2:18 AM, Stephen Reay <php-lists@koalephant.com> wrote:
>>
>> Hi Mike,
>>
>> From a userland perspective I don’t really “get” your proposal.
>>
>> It seems like you’re trying to allow for type conversions in a predictable manner, but in
>> a very different way than php already does that with built in types and interfaces (__toString, the
>> proposed __toArray, plus the various (de)serialiser options)
>>
>> Your proposal seems to imply some kind of automatic method generation by the engine itself
>> (or the examples are all missing that boilerplate??) which is very non obvious to me and I think
>> would be to others too.
>>
>>
>> From my perspective a more obvious solution for this type of thing (and I’m not
>> necessarily sure I’d use the feature myself to be honest) would be a set of interfaces (or magic
>> methods to match __toString but I know they’re less preferred by some these days) to define that a
>> class can be safely cast to another type when used with typed properties/arguments/returns.
>>
>>
>> Cheers
>>
>> Stephen
>
Hi Mike,
I did read your other replies before responding.
__toString is much older than type hints (and especially scalar type hints) in php and wasn’t
really built for that purpose AFAIK, but in ‘weak’ mode (i.e. no strict_types=1) it would be
invoked if the destination type specified a string. I was implying that this behaviour could be
expanded both with other integer casting methods and to allow it to work in ’strict’ mode with
an approach similar to how php works now, rather than suggesting that it works right now.
It’s true you can’t cast to an object (besides stdclass) - but again, my point was not so much
that the functionality already exist, more so that your proposal seems to ignore any history of how
php handles this type of thing, and is - to my eyes - very foreign in its approach. Also, your
proposal seems to only work for an object that effectively represents a single value (otherwise how
does
setValue/getValue work without a property name?) - I’m not sure how many
examples there are of classes that just wrap literally a single value into something else?
With ArrayObject, Exception etc (I assume you mean, when a class extends one) the behaviour is well
understood - while the internals of how it works may differ, it’s conceptually no different than
extending another user land class. Concepts like late static binding, the parent class, etc - how
does for example an overriden method call the ‘built-in’ method? Or are the built-in methods
effectively ‘final’?
If your goal is to allow a typed property/parameter to accept an object and “know” how to
convert it (e.g. passing a hypothetical instance of a Money class to an int (or a
float, if you’re feeling reckless)) I would see it as being closest in concept to how the
JSONSerializable interface works: your class implements the interface, so which defines a method
that must return the given type (e.g., forgiving the horrendous name an Intable
interface might define function toInt(): int. When doing type checks, if it’s an
object implementing that interface, the method is called, similarly to how when an object is used in
a string context, __toString is called if it exists now (but adapted to work when strict_mode=1)
_toString() only works (i.e. to pass an object to a string param/property) right now in lax-mode. I
was suggesting that it (and matching __toInt/etc methods) could be expanded to be called in strict
mode too - but my personal preference would still be that an interface is ’nicer’.
As you point out, there is currently no way to cast to a class besides stdClass. I don’t have much
thought on that, besides that this type of thing sounds more like where a traditional interface
works anyway, to me.