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]

Reply via email to