Comment #0 by jens.k.mueller — 2012-05-08T01:08:27Z
According to TDPL (p. 388, Table 12.1)
a + b
is rewritten to
a.opBinary!("+")(b) or b.opBinaryRight!("+")(a)
Considering operator overloading together with UFCS leads to the following wrong behavior.
struct Foo {}
Foo opBinary(string op)(Foo lhs, Foo rhs) if (op == "+")
{
return Foo.init;
}
unittest
{
Foo a, b;
a + b; // fails to compile even though it should
}
If a + b is rewritten to a.opBinary!("+")(b) first, then UFCS should rewrite it further to opBinary!("+")(a,b). But it seems UFCS is not considered. UFCS should be carried out when the operator is being rewritten.
Comment #1 by dmitry.olsh — 2012-05-31T06:21:54Z
As defined t shouldn't:
UFCS presently only does go from fn(a,b, ...) -> a.fn(b, ...); way.
And arguably rightfully so, as it already may introduce some hijacking.
Comment #2 by timon.gehr — 2012-06-13T12:18:57Z
(In reply to comment #1)
> As defined t shouldn't:
> UFCS presently only does go from fn(a,b, ...) -> a.fn(b, ...); way.
>
Well, no. UFCS transforms a.fn(b, ...) to fn(a,b, ...).
> And arguably rightfully so, as it already may introduce some hijacking.
Comment #3 by dmitry.olsh — 2012-06-13T12:22:05Z
(In reply to comment #2)
> (In reply to comment #1)
> > As defined t shouldn't:
> > UFCS presently only does go from fn(a,b, ...) -> a.fn(b, ...); way.
> >
>
> Well, no. UFCS transforms a.fn(b, ...) to fn(a,b, ...).
My bad, I actually meant it a.fn ---> fn(a,...) way. Which brings us to the point - request is Invalid then?
Comment #4 by timon.gehr — 2012-06-13T12:37:21Z
(In reply to comment #3)
>
> My bad, I actually meant it a.fn ---> fn(a,...) way. Which brings us to the
> point - request is Invalid then?
I don't think it is invalid.
a + b -> a.opBinary!"+"(b) -> opBinary!"+"(a, b);
Probably this is on the borderline between bug and enhancement request -- I think the documentation can be interpreted either way.
Comment #5 by jens.k.mueller — 2012-06-13T14:05:28Z
(In reply to comment #4)
> (In reply to comment #3)
> >
> > My bad, I actually meant it a.fn ---> fn(a,...) way. Which brings us to the
> > point - request is Invalid then?
>
> I don't think it is invalid.
>
> a + b -> a.opBinary!"+"(b) -> opBinary!"+"(a, b);
>
> Probably this is on the borderline between bug and enhancement request -- I
> think the documentation can be interpreted either way.
Which documentation are you referring to? I don't think this is an enhancement. How can it be an enhancement? Are there exceptions when UFCS has to be applied?
Comment #6 by hsteoh — 2019-02-06T22:57:11Z
Correct me if I'm wrong, but according to spec (https://dlang.org/spec/operatoroverloading.html), operator overloading only works for member functions, not for module-level functions. So UFCS wouldn't apply in this case.
Comment #7 by b2.temp — 2019-02-06T23:34:45Z
Yes you're right. Please OP reopen with a better example in case the operator was supposed to be a member func.
Comment #8 by jens.k.mueller — 2019-02-07T21:34:54Z
I think my reasoning back then (almost seven years ago) was that operator overloading just rewrites one syntax into another. In the specific case a + b -> a.opBinary!("+")(b). I thought about this as a purely syntactical lowering which seems to be wrong. Because the compiler seems to actually check whether the template member function actually exists. That's why the chain seems to stop there and UFCS is not performed. Thanks for the clarification.
Back then it was interesting to me as it would have allowed me to implement operators via free functions which I would have liked. I could have even placed them in a different module. Not that you cannot get a similar behavior by passing template arguments but this seemed more involved.