Operator overloading through UFCS doesn't work

Artur Skawina art.08.09 at gmail.com
Mon Oct 15 17:50:40 PDT 2012


On 10/15/12 17:49, Maxim Fomin wrote:
> 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.

Actually, I'm not really in any camp. UFCS has several obvious problems plus likely
quite a few more subtle ones. Ignoring the issues does not make them go away and
the some-compiler-happens-to-implement-it-like-that-today-therefore-thats-how-it-
-must-work arguments, that often appear here, do not really help.

Note that my above "UFCS method must take precedence" statement only describes the
required functionality; handling it like that /by default/ wouldn't probably be a
good idea, as that would make accidental method hijacking possible.
The lookup should be more like
 
 - T.method
 - ufcs_method(T) marked with 'override'
 - while (T = alias this) {
     - T.method
     - ufcs_method(T) marked with 'override'
   }
 - ufcs_method(T) w/o 'override'    
 - while (T = alias this)
     - ufcs_method(T) w/o 'override'
  
with the compiler enforcing the obvious 'override' rules for ufcs_method declarations
(requiring that T isn't opaque when declaring (or calling) UFCS functions is reasonable,
i don't think having 'foo(a)' and 'a.foo()' mean completely different things would work
well together with UFCS). And yes, it wouldn't completely eliminate the possibility of
hijacking - but you'd need three components interacting for it to happen, which would
make it much less likely to occur.

[Note i came up w/ this design while writing this email - it's not necessarily perfect.]


>> And the purpose of UFCS is?... "operator overloading methods" are /not/ special.
> 
> 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.

This is how UFCS works - for "normal" methods. There's no reason to handle op overloads or
other special methods differently. You are arguing for introducing arbitrary restrictions,
which would bring no gain (that i can see right now), but disallow useful functionality.
Yes, there are some issues, but those are not op-overload specific, but UFCS-related.

> 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.

Well, i don't think anybody wants to /override/ existing operators - it's only about
allowing /extending/ the functionality of non-local types, by adding support for additional
ops and/or types. While being able to override existing methods with UFCS would have some
uses, allowing that would also introduce additional problems.
Anyway, if you need to modify how a type's existing ops work you can always sub-type - 
this is also true in the (non-virtual) method case; UFCS is basically just syntax sugar
(which allows you to transparently locally inject methods w/o creating a new type, 
downcasting and handling the (implicit) upcasts (which could be problematic when eg
working with (pointers-to-)structs)).

artur


More information about the Digitalmars-d-learn mailing list