Behavior of opEquals

Timon Gehr via Digitalmars-d digitalmars-d at puremagic.com
Wed Sep 9 12:20:27 PDT 2015


On 09/09/2015 01:32 AM, Jonathan M Davis wrote:
> 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.

Lowering transforms D code to other D code.

See http://dlang.org/operatoroverloading.html :

We have that e.g. "-e" gets rewritten to "e.opUnary!("-")()".
"e.opUnary!("-")()" is D code. To specify the semantics implemented in 
DMD, the rewrite should be __traits(getMember,e,"opUnary")!("-")() 
(assuming that the parser is fixed so it can actually parse this, which 
would be useful in its own right.)

>>> 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. ...
>
> There would be no way to disambiguate overloaded operators if an
> operator were overloaded in multiple modules. ...
> ...

Yes, there would be. Just use aliases. (Also, overloaded operators are 
not actually that likely to cause conflicts, because they are best 
written to match a suitably constrained set of types, just like other 
functions.)

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

No, it does not force you to do that.

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

I think that's universally understood, but I don't see how this relates 
to the issue at hand.

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

UFCS and this ad-hoc terminology do not describe separate things.

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

(Straw man.)

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

I agree with this part, overloaded operators are just such functions.

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

This is not distinct from being able to declare functions operating on 
built-in types or someone else's types that have other unsuitable names. 
Also, in case you missed it, I also briefly promoted the idea that 
built-in types should define the operator overloading functions in order 
to make treatment of operators uniform (as far as the specification is 
concerned, the compiler could just rewrite the special members to 
whatever internal representation it uses now for the built-in types). In 
particular, "+", "-" and "/" can't be overloaded externally on strings 
in such a setting.

> What do you want next?

(That's a nice way of introducing a straw man.)

> To be able to declare constructors for someone else's type?

That's not even close to being similar.

> That kind of stuff

:o)

AFAICT, they were just clustered together randomly in order to 
artificially boost the argument.

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

I don't see where you get this idea. It should be noted that operator 
overloading isn't even that common and basically all legitimate usages 
are obvious. (They are those cases where a operator is the most natural 
name for a function.)

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

On 09/09/2015 01:32 AM, Jonathan M Davis wrote: (moved from above)
> I really don't see any reason why it would even make sense to declare
> operators separately from a type.

One reason is that single dispatch can be awkward. A textbook example 
would be: you have a set of special matrix types (dense, sparse, 
diagonal, triangular, column-first, row-first, etc.), and now want to 
implement multiplication efficiently for all pairs of types via static 
dispatch. Why should I have to jump through hoops just to be able to use 
suitable function names that are associated with the wanted call syntax?

Another reason is that it is annoying that overloaded operators choose 
the calling convention for you, asymmetrically only for the first argument.

It certainly shouldn't be hard to produce more of those examples. 
Non-orthogonal features tend to cause subtle (and less subtle) pain points.


It would be better already if UFCS only worked for overloaded operators 
if the type and the operator where defined in the same module, but I 
really don't see the point of adding arbitrary limitations to the 
language. There might be legitimate use cases.

> There is _nothing_ in the spec which supports UFCS having anything to do
> with overloaded operators

On 09/09/2015 01:32 AM, Jonathan M Davis wrote: (moved from the 
beginning of the post)
> The spec says _nothing_ about UFCS
> applying to overloaded operators or that UFCS would apply to lowered
> code in any way shape or form.
> ...
>

Please stop palindrome-posting. (This is a general tendency in your 
posts, I wouldn't have brought it up otherwise: they (approximately) 
start with topic A, go to topic B, then C, return to B and then finish 
with A. Together with the missing emphasis on conciseness, it can get a 
little bit tiring at times.)

If you read http://dlang.org/function.html#pseudo-member carefully, 
nowhere is it explicitly mentioned that it works with built-in types or 
structs, or with classes named "NoUFCS". Would you also claim that the 
intention of the specification to support UFCS for those types is 
questionable? Your argument seems to apply equally well to those cases.

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

I might do that eventually, but there are more important things to 
consider at this point.



More information about the Digitalmars-d mailing list