Operator/concept interoperability
Mason McGill via Digitalmars-d
digitalmars-d at puremagic.com
Tue Jun 3 15:40:06 PDT 2014
On Tuesday, 3 June 2014 at 22:05:29 UTC, TheFlyingFiddle wrote:
> Well one reason for this is that unlike methods it is hard to
> resolve ambiguity between diffrent operator overloads that have
> been defined in diffrent modules.
>
> Example: 2D-vectors
> //vector.d
> struct Vector
> {
> float x, y;
> }
>
> //cartesian.d
> Vector opBinary(string op : "+")(ref Vector lhs, ref Vector rhs)
> {
> //Code for adding two cartesian vectors.
> }
>
> //polar.d
> Vector opBinary(string op : "+")(ref Vector lhs, ref Vector rhs)
> {
> //Code for adding two polar vectors.
> }
>
> //main.d
> import polar, vector;
> void main()
> {
> auto a = Vector(2, 5);
> auto b = Vector(4, 10);
>
> auto c = a + b; //What overload should we pick here?
>
> //This ambiguity could potentially be resolved like this:
> auto d = polar.opBinary!"+"(a, b);
> //But... This defeats the whole purpose of operators.
> }
Interesting point. However, I believe this is also the case for
ordinary functions used with UFCS:
// cartesian.d
Vector add(ref Vector lhs, ref Vector rhs)
{ /* Code for adding two cartesian vectors. */ }
// polar.d
Vector add(ref Vector lhs, ref Vector rhs)
{ /* Code for adding two polar vectors. */ }
// main.d
import polar, vector;
void main()
{
auto a = Vector(2, 5);
auto b = Vector(4, 10);
auto c = a.add(b); // What overload should we pick here?
// The fully qualified form looks quite different,
// but it's rare, and intentionally explicit about what's
// really going on, so that's OK.
auto d = polar.add(a, b);
}
It strikes me that ambiguous cases are not nearly as common as
unambiguous cases, especially if you use selective imports.
I believe Julia uses a re-write rule for its operators: the first
thing the compiler does when evaluating an operator expression is
re-write it as a function call; after that, all the language's
resolution rules apply as they would to any other function call.
D could easily take this approach, simplifying the language while
maintaining backwards-compatibility.
> Side note:
>
> You can achieve what you want to do with template mixins.
>
> ...
>
> While this implementation is not as clean as global operator
> overloading it works today and it makes it very simple to add
> operators to new types of grids.
Thanks for the example. This is actually my current solution :)
However, as you allude to, I'm not a huge fan of it because
1) It requires boilerplate on the part of library users.
2) It makes you scratch your head and go "Huh; operator and
non-operator functions have different compile-time polymorphism
capabilities; why is that?"
More information about the Digitalmars-d
mailing list