Operator overloading through UFCS doesn't work

Maxim Fomin maxim at maxim-fomin.ru
Mon Oct 15 08:49:59 PDT 2012


On Monday, 15 October 2012 at 11:01:13 UTC, Artur Skawina wrote:
> UFCS has pros and cons. I could agree that it has problems and 
> should be removed
> from the language completely. But if the feature is there, it 
> should work, w/o any
> unnecessary special cases.

Special cases would be created by any decision, the only question 
is which feature is discriminated - alias this, UFCS or something 
else (currently UFCS is).

> An overloaded operator is just another normal method; you get 
> the same type of
> problems when dealing with "normal" methods - eg in types 
> having an "alias this" -
>  an UFCS "method" must take precedence over one reachable via 
> the alias - just like
> in the overloaded op case. The only sane alternative would be 
> disallowing UFCS
> for types with an "alias this" (which would be a severe 
> limitation).

You seem to be in the second camp (UFCS free function takes 
precedence over alias this, if declared). I am not against, just 
to note.

> And the purpose of UFCS is?... "operator overloading methods" 
> are /not/ special.
> artur

The point is that when you want to define UFCS free functions 
like opUnary, you want not only to call them like 
a.opUnary!"++"() but to code like ++a. That is the key issue here 
and that makes the whole case special.

In other words: with UFCS you have an option: to call your 
function as it was a method of some type. And anyone has this 
option. The only problem is namespace conflict which can be 
easily avoided. But you still has the option.
With UFCS operator overloaded functions you have *two* options: 
to call free functions as methods as usual *and* to use 
struct/class with many operators in a manner you want. But if 
anyone of that type users define his set of operator overloaded 
functions *you lose the second option* which makes the proposal 
to allow simultaneous access to single resource pointless.

Consider this:

---somelib.d---
struct A { void foo() {} }

---otherlib.d---
void bar(A a) {}

---mycode.d---
// blah, foo and bar are taken
// solution - choose other name
void baz(A a) {}
---------------

Now assume, UFCS operator overload is possible.

---somelib.d---
struct A { int i; int j; }

---mycode.d---
int opUnary(string T : "++")()
{
     return ++i;
}
...
++a;
...
-------------

At some point of time the owner of somelib.d changes code (or 
anyone whom code you import define such functions):

---somelib.d---
struct A {
int i; int j;
int opUnary(string T : "++")()
     {
         return ++j;
     }
}

---mycode.d---
int opUnary(string T : "++")()
{
     return ++i;
}
----------------
So, you lost your option to use A in expressions and call your 
function which is the point here. You cannot invent +my_unary+ 
operator. Neither you can rebind ++ to some function other than 
opUnary.

Yes, it also may happen with regular function, when you lose 
ability to give a function some specific name you want (like 
"create", "foo" etc.). But in case of UFCS operators you lose not 
only some function name ("opUnary") but corresponding expression 
as well (++).

This means that it makes sense to allow only one set of 
opUnary/opBinary/.. etc. of functions (anyway, only one can 
define them and use with operators) and the most suitable place 
is declaration of their type.


More information about the Digitalmars-d-learn mailing list