Behavior of opEquals

Jonathan M Davis via Digitalmars-d digitalmars-d at puremagic.com
Tue Sep 8 16:32:28 PDT 2015


On Tuesday, 8 September 2015 at 20:55:35 UTC, Timon Gehr wrote:
> On 09/08/2015 06:49 PM, Jonathan M Davis wrote:
>> Sure, it _could_ be implemented that way, but the only reason I
>> see to do that is if we're specifically looking to support 
>> defining
>> overloaded operators outside of the types that they apply to. 
>> I can't
>> think of anything else that would be affected by it.
>> ...
>
> The compiler does not match the specification. I see no reason 
> to change the specification here, but it would be easy.

I don't know where you get this idea. The spec says _nothing_ 
about UFCS applying to overloaded operators or that UFCS would 
apply to lowered code in any way shape or form.

>> Regardless, I honestly think that it would be a very bad 
>> technical
>> decision to support defining overloaded operators outside of 
>> the type
>> itself - _especially_ when you take into account operators 
>> that have
>> defaults generated by the compiler (e.g. opEquals), since that 
>> would
>> allow a third party to change what your code does by adding 
>> their own
>> overloaded operator.
>
> Well, how? "Overloaded operators" are just specially named 
> functions that support an additional call syntax. There are no 
> strange issues with modularity that somehow only apply to 
> overloaded operators. UFCS calls can never ignore methods of 
> the type. It does not matter how they were generated. Was this 
> your strongest point against having the compiler combine UFCS 
> and operator call syntax in the straightforward fashion?

There would be no way to disambiguate overloaded operators if an 
operator were overloaded in multiple modules. foo + bar has no 
import paths involved in it at all. So, what would you do, write 
opBinary!"+"(foo, bar) instead? That's downright hideous, and it 
relies on you using the function call to emulate the operator 
correctly. For something like bar++, you'd be even more screwed, 
because it doesn't lower to a simple function call.

UFCS is already enough of a problem on its own. It has some 
benefits, but it doesn't work when conflicts come into play, 
forcing you to just call the function normally, and its overload 
rules are such that it doesn't actually prevent hijacking in all 
cases (e.g. your code could suddenly change behavior, because you 
used UFCS with a type that then had a function with the same name 
and parameters added to it). And overloaded operators are closely 
tied to what a type does, whereas functions are far more diverse. 
So, there's a lot more to be gained with UFCS than with declaring 
overloaded operators separately from a type. I really don't see 
any reason why it would even make sense to declare operators 
separately from a type. So that you can declare multiple 
overloads of it for when you import different modules? That would 
just be plain confusing and incredibly error-prone. And if the 
problem is that you're dealing with someone else's type, then 
just declare a function to do what you want and be done with it. 
And do you really want people to be able to overload stray 
operators for stuff like strings and then write code that uses + 
and - and / or whatever on them? That would be ludicrous. It's 
one thing for people to do that with their own types. It's quite 
another to do that to built-in types or to someone else's types. 
What do you want next? To be able to declare constructors for 
someone else's type? That kind of stuff is part of the type, and 
allowing 3rd parties to declare it as well just makes it that 
much harder to figure out what's going on. At least when using 
UFCS, it's the exception that the function is on the type, so the 
overload rules don't usually shoot you in the foot (though they 
can), and you know to look elsewhere for the function just like 
you would with a function that was called normally. It's the 
complete opposite with operators.

We have overloaded operators so that someone who is writing a 
user-defined type can make it act like a built-in type where 
appropriate. Allowing 3rd party code to declare overloaded 
operators for a type doesn't help with that at all.

There is _nothing_ in the spec which supports UFCS having 
anything to do with overloaded operators and nothing to support 
overloading operators separately from a type. And I recall Walter 
Bright stating that it was on purpose that you can only overload 
operators on a type. So, even if the spec _could_ be interpreted 
to mean that you should be able to declare overloaded operators 
separately from the type that they apply to, that's _not_ its 
intention, and you're going to have to convince Walter if you 
want anything else.

- Jonathan M Davis


More information about the Digitalmars-d mailing list