In current D, overloading operator like "+" with external function is prohibited. There is the rationale [1] (see second paragraph).

BUT this rationale is totally UNCONVINCING. I can say that resume of rationale is: "it is impossible because it brakes some C++ patterns and behaviour". Further I will try to demonstrate such resume.

Let start with an example where external operator overloading can be useful. Imagine, we want to create some lazy matrix algebra, where all operation return new object of corresponding to operation subtype. E.g. `transpose` returns `TransposedMatrix`, where `opIndex` just call `opIndex` of internally stored matrix with switched order of indices, `plus` returns `MatrixSum`, where `opIndex` just calculated the sum of two corresponding elements of stored matrices and so on. Of course we want that any resulting subtypes can interact with each other, so we require common "denominator". There are two ways compile-time duck-typing with template bloating, or common interface (yeah, with garbage collection in the simplest implementation), but the last allows us to have some run-time parameters. So regard common interface approach: our interface should be minimal as possible, for our purposes having `rows`, `columns` and `opIndex` seems to be sufficient.
OK, we have:
Matrix plus(Matrix A, Matrix B)
    final class MatrixSum : Matrix
    return new MatrixSum(A, B);
C=plus(A, B);
(Or even `` because of UFCS). And this works perfect.
If we want some sugar like `C=A+B` we are in trouble. We can create function `Matrix opBinary(string op)(Matrix A, Matrix B) if(op == "+")`, it even can be called with full name, but not with "+" operator, because now compiler just doesn't look for external function as overload for operator. If we want have this as member we should ad opBinary to our interface, what leads to some new trouble: now each type should have opBinary, but how we should implement this for example for `TransposedMatrix` or even more interesting (because of kind of type recursion) how we should implement it for `MatrixSum`. OK, me and Mathias Lang have found workaround for my particular case we should implement (and probably make `final`) opBinary for `Matrix` interface, which in its turn calls function `plus` we already described. But its create lines of code for nothing, because operators are considered as too exceptional.

Let us return to rationale.
First point is "Operator overloading can only be done with an argument as an object". Why??? it seems to come from "C++ mind", before UFCS was implemented in language. If we have `!string` and `` working, what wrong with `A+B` or `2*B` (where A and B matrices). Moreover for case like `2*B` (multiplication by scalar) we should have a bit ugly `opBinaryRight(string op)(double scalar)` as member function. It isn't convinced.

Second point is "Operator overloads USUALLY need access to private members of a class". It has nothing common with operator, it is only demonstrate our C++ behave to work with private members in operator. But having access to private member isn't necessary for operator to work. In my example `plus` function uses only public API of my classes, it can be done such way in many, many cases. And also often this external function would be placed in the same module, so it is already have "friend" in such case. If external function in external module want to have access to private API, it is only a sign of bad design, and should be a problem of particular programmer how to rework the design, not case for compiler to step in. It isn't convinced.

Third point is totally unnecessary because we don't need access to private members.

So, no one of point convinces me.

What can really can convince me that rationale like: "if we do so total parsing algorithm will be corrupted, and we can't use D any-more", or at least "with that feature compiler becomes 100 times slower".

So if someone has real rationale not to have operator overloading as external function I'm curios to arguments.


Reply via email to