On Fri, 17 Dec 2021 at 00:25, Larry Garfield <la...@garfieldtech.com> wrote:
>
> On Thu, Dec 16, 2021, at 1:24 PM, Andreas Hennings wrote:
>
> > I see the distinction in overloading based on the object type on the
> > left, vs overloading based on parameter types.
> >
> > For a method call $a->f($b), the implementation of ->f() is chosen
> > based on the type of $a, but not $b.
> > For an operator call "$a + $b", with the system proposed here, again,
> > the implementation of "+" will be chosen based on the type of $a, but
> > not $b.
> > For native operator calls, the implementation is chosen based on the
> > types of $a and $b, but in general they are cast to the same type
> > before applying the operator.
> > For global function calls f($a, $b), the implementation is always the same.
> >
> > In a language with parameter-based overloading, the implementation can
> > be chosen based on the types of $a and $b.
> >
> > This brings me back to the "symmetry" concern.
> > In a call "$a->f($b)", it is very clear that the implementation is owned by 
> > $a.
> > However, in an operator expression "$a + $b", it looks as if both
> > sides are on equal footing, whereas in reality $a "owns" the
> > implementation.
> >
> > Add to this that due to the weak typing and implicit casting,
> > developers could be completely misled by looking at an operator
> > invocation, if a value (in our case just the left side) has an
> > unexpected type in some edge cases.
> > Especially if it is not clear whether the value is a scalar or an object.
> > With a named method call, at least it is constrained to classes that
> > implement a method with that name.
>
> The RFC covers all of this, and the way it works around it.  Absent method 
> overloading (which I don't expect any time soon, especially given how 
> vehemently Nikita is against it), it's likely the best we could do.
>
>
> > In a class Matrix, operator(Matrix $other): Matrix {} can be declared
> > to always return Matrix, and operator(float $factor): float {} can be
> > declared to always return float.
> > However, with a generic operator(mixed $other): Matrix|float {}, we
> > cannot natively declare when the return value will be Matrix or float.
> > (a tool like psalm could still do it)
>
> I... have no idea what you're talking about here.  The RFC as currently 
> written is not a "generic operator".  It's
>
> operator *(Matrix $other, bool $left): Matrix
>
> The implementer can type both $other and the return however they want.  That 
> could be Matrix in both cases, or it could be Matrix|float, or whatever.  
> That's... the same as every other return type we have now.

Basically the same as others have been saying in more recent comments.

In a class Matrix, you might want to implement three variations of the
* operator:
- Matrix * Matrix = Matrix.
- Matrix * float = Matrix.
- Matrix * Vector = Vector.
Same for other classes and operators:
- Money / float = Money
- Money / Money = float
- Distance * Distance = Area
- Distance * float = Distance

Without parameter-based overloading, this needs union return types, IF
we want to support all variations with operators:
- Matrix * (Matrix|float|Vector) = Matrix|Vector.
- Money / (Money|float) = float|Money
- Distance * (Distance|float) = Area|Distance

Which gives you a return type with some ambiguity.

With methods, you could have different method names with dedicated return types.
The naming can be awkward, so I am giving different possibilities here.
- Matrix->mulFloat(float) = Matrix->scale(float) = Matrix
- Matrix->mul(Matrix) = Matrix::product(Matrix, Matrix) = Matrix
- Matrix->mulVector(Vector) = Vector

To me, the best seems a method name that somehow predicts the return type.

Possible solutions for the developer who is writing a Matrix class and
who wants to use overloaded operators:
- Accept the ambiguity of the return type, and use tools like psalm to
be more precise.
- Only use the * operator for one or 2 of the 3 variations (those that
return Matrix), and introduce a regular function for the third:
  - Matrix * Matrix|float = Matrix
  - Matrix->mulVector(Vector) = Vector

This "concern" is not a complete blocker for the proposal.
For math-related use cases like the above, the natural expectation to
use operators can be so strong that we can live with some return type
ambiguity.

-- Andreas


>
> --Larry Garfield
>
> --
> PHP Internals - PHP Runtime Development Mailing List
> To unsubscribe, visit: https://www.php.net/unsub.php
>

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php

Reply via email to