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

  106892
September 6, 2019 08:20 php-lists@koalephant.com (Stephen Reay)
> 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.