Argumnentation against external function operator overloading is unconvincing
HaraldZealot via Digitalmars-d
digitalmars-d at puremagic.com
Wed Sep 21 10:57:17 PDT 2016
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:
```d
Matrix plus(Matrix A, Matrix B)
{
final class MatrixSum : Matrix
{...}
...
return new MatrixSum(A, B);
}
...
C=plus(A, B);
```
(Or even `C=A.plus(B)` 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 `1.to!string`
and `A.plus(B)` 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.
[1] http://dlang.org/rationale.html
More information about the Digitalmars-d
mailing list