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