On Tue, 19 Nov 2019 at 03:19, Mike Schinkel <m...@newclarity.net> wrote:
> Should we make decisions about future language enhancements based on > conflicting and impossible to forecast predictions, or when a significant > subset of PHP developers see value in a feature for their use-cases *and* > others can simply ignore if they do not want to use it? > Neither. We should discuss the advantages of the feature, the potential costs, and whether other features would be even better. I challenge that assertion that having a huge number of magic or standard > methods is the *"only"* way this provides benefit. > > Not the only way it can bring *any* benefit, but the only way it can bring the *particular* benefit of eliminating the need to agree method names across code bases. I think that's where this conversation has broken down a bit, which may be my fault: I wasn't intending to argue against all the possibilities of the feature, only the specific arguments you were raising. We disagree over whether (array)$foo would be used more consistently than meaningful method names, so maybe we should leave that there, and look at some other pros and cons of the feature. > Since conversion to array from object is a common need just this one > method could provide a similar level of benefit that __toString() already > provides. > > What makes __toString() worthy of a special case in my mind is that there are fairly common scenarios where variables are _implicitly_ cast to string: in double-quoted strings, echo, etc. Having the language be able to automatically call a particular method in those situations is therefore more valuable. I think I'd actually be more receptive to a proposal to allow _all_ casts to be overloaded, rather than adding array as a second special case, because *implicitly* casting to array doesn't seem like it would be any more common than other types. > Yes, if your class is named Transaction then isSuccessful() probably *is* > a better name than __toBool(). > > > But if your class name itself is isSuccessful()? > > Yes, I would see that as a better example. I think operator overloading in general makes sense when the object itself can be thought of as a special-case of the primitive it's emulating operators for. So in this case, the IsSuccessful class would be "a special kind of boolean"; and the hypothetical List or Collection classes I mentioned a couple of days ago would be "a special kind of array". We even have that in PHP for built-in types: GMP objects can now be used with mathematical operators like $foo * $bar, and those operations do what you'd expect them to do on an integer or float. Operator overloading can also be used just as a cute way of spelling something - probably most famously, C++ uses the << and >> operators for writing to and reading from streams, even though they're actually overloads of the bit-shift operator. This kind of use is, I would say, more controversial - going back to consistency, it's easier to reason about code if $foo * $bar always does some kind of multiplication than if it's been overloaded to mean "$foo is the star of $bar". Overloading of cast operators is no different - the clearest use cases for __toString() are where the whole class basically represents a piece of text, and the more controversial are where (string)$foo is actually a cute spelling of one method on a complex class. That's not necessarily a reason to not add a feature - any feature can be abused - but it potentially makes it harder for users to understand each other's code, and that's a cost we should at least consider. > Let me count the ways. Here are several examples: > > https://gist.github.com/mikeschinkel/361bbcf44da1dac0da6afd786b6b8c3a > > > A great example of this is the AllowedHtml class I wrote for the above > gist whose sole purpose is to streamline the specification of allowed HTML > using to KSES library. > > This is an interesting example. On the one hand, there is only one array ever going to be produced by that class; but on the other hand, the ultimate use of it is explicitly passing to a function that expects a different type. Assuming the same behaviour as __toString, the code shown would give an error under strict_types=1, and need changing to wp_kses((array)$allowed_html) A different interpretation would be that this is the Builder Pattern, and the target type happens to be an array rather than an object. So you might decide that the consistency you really needed is that all builders should have a build() method, and the last line of the example would become: $clean_html = wp_kses($_POST[ 'content' ] ?? null, $allowed_html_builder->build()); That doesn't mean the version you wrote is *wrong*, but should make us consider why one version deserves special treatment by the language and the other one doesn't. Regards, -- Rowan Tommins [IMSoP]