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