On Wed, Sep 18, 2024 at 6:11 PM Rowan Tommins [IMSoP] <imsop....@rwec.co.uk> wrote:
> On Wed, 18 Sep 2024, at 15:19, Christoph M. Becker wrote: > >> Maybe it would be "useful enough" to just restrict to left-hand side: > > > > In my opinion, this is the only reasonable way to implement operator > > overloads in PHP. It is easy to understand, and what can easily be > > understood is easy to explain, document, and to reason about. I do not > > understand why we're talking about commutative operations; even the > > inconspicuous plus operator is not commutative in PHP > > (https://3v4l.org/nQcL5). > > There are really three different things we shouldn't confuse: > > 1) Commutativity of the operation, as in $a + $b and $b + $a having the > same result. As you say, this is a non-goal; we already have examples of > non-commutative operators in PHP, and there are plenty more that have been > given. > > 2) Commutativity of the *resolution*. This is slightly subtler: if $a and > $b both have implementations of the operator, should $a + $b and $b + $a > call the same implementation? We can say "no", but it may be surprising to > some users that if $b is a sub-class of $a, its version of + isn't used by > preference. > > 3) Resolution when *only one side has an implementation*. For instance, > how do you define an overload for 1 / $object? Or for (new DateTime) + (new > MySpecialDateOffset)? It's possible to work around this if the custom class > has to be on the left, but probably not very intuitive. > > It's also worth considering that the *resolution* of PHP's operators > aren't currently determined by their left-hand side, e.g. int + float and > float + int both return a float, which certainly feels like "preferring the > float implementation regardless of order", even if PHP doesn't technically > implement it that way. > > > How about doing it like in Python, where there is `__add__` and `__radd__`? And the engine could call $op1->add($op2) if $op1 is an object and `add()` is implemented, or otherwise call $op2->rightAdd($op1) if $op2 is an object and `rightAdd()` is implemented, or otherwise fail with an error. We could have (distinct) interfaces for both `add()` and `rightAdd()`. Or use magic methods like `__add()` and `__rightAdd()` to allow stricter types instead of `mixed` on the other operand. I think there is no extra complexity for the engine by using magic methods or interfaces. -- Alex