Re: [Pre-RFC Discussion] User Defined Operator Overloads (again)
| From: | Larry Garfield | Date: | Wed, 18 Sep 2024 01:46:23 +0000 |
| Subject: | Re: [Pre-RFC Discussion] User Defined Operator Overloads (again) | ||
| References: | 1 2 3 4 5 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-125612@lists.php.net to get a copy of this message | ||
On Tue, Sep 17, 2024, at 3:14 PM, Jordan LeDoux wrote:
>> I think it's absolutely possible - and desirable - to choose a philosophical position
>> on that spectrum, and use it to drive design decisions. The choice of "__add" vs
>> "operator+" is one such decision.
>>
>
> Ah, I see. I suppose I never really entertained an idea like this
> because in my mind it can't even handle non-trivial math, let alone the
> sorts of things that people might want to use overloads for. Once you
> get past arithmetic with real numbers into almost any other kind of
> math, which operators are meaningful, and what they mean exactly,
> begins to depend a lot on context. This is why I felt like even if we
> were limiting the use cases to math projects, things like commutativity
> should not necessarily be enforced.
>
> The line
$a + $b and $b + $a
> are SUPPOSED to give different results
> for certain types of math objects, for instance. The line $a -
> $b and
> $b - $a more obviously give different results to most people,
> because
> subtraction is not commutative even for real numbers.
>
> My personal opinion is that the RFC should not assume the overloads are
> used in a particular domain (like real number arithmetic), and thus
> should not attempt to enforce these kinds of behaviors. But, opinions
> like this are actually what I was hoping to receive from this thread.
> This could be the way forward that voters are more interested in, even
> if it wouldn't be my own first preference as it will be highly limiting
> to the applicable domains.
I'm not sure where exactly in this thread to put this, so I'm putting it here...
Rowan makes an interesting point regarding operators vs operations. In particular, the way the
<=> logic is defined, it is defining an operation: comparison. Using it for anything other
than ordering comparison is simply not viable, nor useful. It's defining a custom
implementation if a specific pre-existing action.
For all the other operators, the logic seems to be defined for an operator, the behavior of which is
"whatever makes sense in your use case, idk." That is, to use Rowan's distinction, a
philosophically different approach. Not a bad one, necessarily. In fact, I think it's a very
good one.
But, as they are different, perhaps that suggests that comparison should instead not be implemented
as an operator overload per se, but as a named magic method. The existing logic for it is, I think,
fine, but it's a fair criticism that you're not defining "what happens for a
method-ish named <=>", you're defining "how do objects compare." So I
think it would make sense to replace the <=> override with a __compare(mixed $other):
int, which any class could implement to opt-in to ordering comparisons, and thus work with
<, >, ==, <=>, etc. (And, importantly, still keep the "specify the type(s) you
want to be able to compare against" logic, already defined.)
A similar argument could probably be made for ==, though I've not fully thought through if I
agree or not. Again, I think the previously defined logic is fine. It would be just changing the
spelling from operator ==(mixed $other): bool to public function __equals(mixed
$other): bool. But that again better communicates that it is a core language behavior that
is being overridden, rather than an arbitrarily defined symbol-function-thing with domain-specific
meaning.
There was an RFC for a Comparable interface back in the stone age (2010), but it looks like it never
went to a vote: https://wiki.php.net/rfc/comparable
Arguably, this would then make more sense as a stand-alone RFC that happens to reuse a lot of the
existing code and logic defined for operator overloads, which are all still just as valid.
That does not apply to the arithmetic, bitwise, or logic operators. Overriding + or / for a
specific domain is not the same, as you're not hooking into engine behavior the way <=>
or == are. For those, I'd prefer to stick to the current/previous implementation, with the
operator keyword, for reasons I explained before.
Jordan, does that distinction make sense to you?
--Larry Garfield