Re: [PHP-DEV] Operator overloading for userspace objects

This is only part of a thread. view whole thread
February 7, 2020 20:48 (Andrea Faulds)
Hi Johannes,

Thank you for your points! I think you point out some overlooked issues.

Johannes Schlüter wrote:
> Which one is being called? - Vector's or Matrix's. How will your > vector know about my Matrix? > > The way C++ solves this is by allowing non-member functions as > operators. > > #include "vector3.h" // provides class Vector3 > #include "matrix.h" // provides class Matrix, potentially > // from a different vendor > > Matrix operator*(const Vector3 &lhs, const Matrix &rhs) { > // I can provide this myself if neither Vctor's nor > // Matrix's vendor do > return ...; > } > > int main() { > Vector3 vec{...}; > Matrix matrix{....}; > > // works > auto result = vec * matrix; > }
I wonder if it would be a good idea, if we do want operator overloading in PHP, to implement a similar mechanism for this. Perhaps type-specific overloads could be registered via some special function call or declaration, something vaguely like: class Vector { public function __construct() { php\register_overload($this, Matrix::class, '*', function ($a, $b) { /* multiplication implementation here */ }); } } The engine could then do type-matching for you, and would implement commutativity for you if the operator is commutative, so `$someVector * $someMatrix` would call the above function, but so would `$someMatrix * $someVector`. (Note: to support matrix multiplication, I guess commutativity must be overridable. Also, I have forgotten whether multiplying a matrix and a vector is commutative or not :p) I think this approach would be less messy than having to implement full type matching on both sides of a type pair, for a number of reasons: * Instead of Vector having to have an implementation of __mul which checks for Matrix, and Matrix having to have an implementation of __mul which checks for Vector, just one of these types can call register_overload with a single implementation (because the operation is commutative). * Whether two types can be used with a particular operator is clear: either there is such a pair registered, or there is not, and PHP can give appropriate error messages. It is unlikely there will be an issue where one side has __mul but it just throws an exception or somethig. Also, in a case like `$a * $b`, $a can implement support for $b without $b having to support $a, while at the same time $b can implement support for some unrelated other type, without `$b * $a` not working (with the current proposal, imagine $a's __mul handler supporting $b but not vice-versa). * The engine can see conflicts (one class declares an overload involving the other class, and vice-versa) and warn about them, rather than `$a * $b` silently having completely different behaviour to `$b * $a`. This is not to say we necessarily should implement this, but it may be worth thinking about… Thanks, Andrea