October 17, 2012
On 10/17/2012 01:51 PM, Maxim Fomin wrote:
> On Wednesday, 17 October 2012 at 11:11:26 UTC, Timon Gehr wrote:
>> On 10/14/2012 09:14 AM, Maxim Fomin wrote:
>>> On Sunday, 14 October 2012 at 07:01:30 UTC, Tommi wrote:
>>>> Actually, it seems that alias this has precedence over UFCS. So, a
>>>> free function opUnary wouldn't ever suit better than an actual method
>>>> opUnary of the thing referred to by that alias this.
>>>
>>> http://dpaste.dzfl.pl/d0a4431d
>>>
>>> Free function doesn't suit better than actual method. The issue is
>>> absence of the actual method.
>>>
>>> opUnary method has priority over alias this, which does make sense
>>> because alias this is chosen only when it is impossible to apply
>>> operation over A type. If this request is approved and compiler has
>>> opUnary definition outside type (which suits better then alias this)
>>> such function would hijack alias this. If not, there is a new case when
>>> something is going special than at usual cases and only for the purpose
>>> of writing operator overloading methods outside the body of the type.
>>
>> The goal must be to get rid of all special behaviour that can result in
>> strange interactions.
>> Add the suitable operator function templates to built-in types. Always
>> rewrite operators to operator function calls. Problem solved.
>> ...
>
> You have a struct with alias this to int without overloaded operators.
> It (say, struct.d) contains code with structure increments. Some other
> module (say bob.d), which import the structure, defines function
> supposed to overload opUnary. If operators are always rewritten to
> function calls, now function should be called in module bob.d, as well
> as in struct.d if they are compiled together. It certainly not what
> author of struct.d expected. The case can be even more interesting, if
> alias this in struct.d were absent at a time when bob.d was written and
> at some point of future Bob is updating his sources.


Members do not cause conflicts with free functions.
Alias this takes precedence as it is a member of the type.
What is the issue?
October 17, 2012
On 10/17/12 12:46, Timon Gehr wrote:
> On 10/15/2012 01:00 PM, Artur Skawina wrote:
>> ...
>>
>> 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).
>> ...
> 
> Just no. Why make symbol lookup even more complicated just in order to add an strange exception to the language that either enables new forms of hijacking or would be a severe limitation?

Like i said in a later message - I think the /functionality/ should be available, how it's handled is a different issue. The reason why I'd want UFCS take priority over alias-this is that in the presence of multiple aliases and external components method hijacking is actually likely to become a problem. Eg a newer /library/ version can silently hijack an apps UFCS extension "method". Plus, the aliases can severely limit the available ufcs namespace; and the compiler won't even flag many conflicts as errors.

UFCS is a much cheaper alternative to sub-typing, having it work for as many cases
as possible is important. Think: app that uses an own GUI module on top of a themeing
library on top of a GUI widget toolkit on top of a basic windowing system. Being able
to extend functionality (by adding just a method or two, in the app) without having to
create an extra type hierarchy and dealing with all the conversion issues could be very
useful.

UFCS is just optional syntax sugar, so I can buy the 'no changes for this' argument - only then I fear that it's usefulness decreases to the point where the cost is no longer justified. For the cases where creating a new type is overkill, one can always use a free function.

[Yeah, I'm ignoring the 'functional-style' aspect, I know. UFCS might help there,
 but a DSL would be better long-term solution IMHO, and would also avoid the
 @property related issues (extra parens). But that's off-topic, at least in this thread.]

artur
May 24, 2016
On Saturday, 13 October 2012 at 22:58:56 UTC, Timon Gehr wrote:
> Afaik free-function operator overloads (but not in the context of UFCS) were considered and turned down because D did not want to get amidst discussions about adding Koenig lookup. UFCS does not do Koenig lookup.

I don't get it, aren't the current symbol lookup rules enough to make free function operator overloads useful? To me it looks like they are.

Sorry for digging up this thread, just getting irritated by a restriction that seems pointless and arbitrary.

Overloaded operators would suffer from the same potential abuses other methods are subjected to if UFCS was enabled, nothing more as far as I can see.
May 24, 2016
On Tuesday, May 24, 2016 23:19:32 Elie Morisse via Digitalmars-d-learn wrote:
> On Saturday, 13 October 2012 at 22:58:56 UTC, Timon Gehr wrote:
> > Afaik free-function operator overloads (but not in the context of UFCS) were considered and turned down because D did not want to get amidst discussions about adding Koenig lookup. UFCS does not do Koenig lookup.
>
> I don't get it, aren't the current symbol lookup rules enough to make free function operator overloads useful? To me it looks like they are.
>
> Sorry for digging up this thread, just getting irritated by a restriction that seems pointless and arbitrary.
>
> Overloaded operators would suffer from the same potential abuses other methods are subjected to if UFCS was enabled, nothing more as far as I can see.

If UFCS doesn't work, because there are two free functions with the same name which take the same arguments, then you can differentiate between them by not using UFCS and using their full import paths, or you can alias them so that they don't have the same name. Neither of those would be possible with operator overloading. If overloaded operators were allowed as free functions, then if there were ever a symbol conflict, you'd be screwed.

- Jonathan M Davis

May 25, 2016
On Tuesday, 24 May 2016 at 23:43:46 UTC, Jonathan M Davis wrote:
> On Tuesday, May 24, 2016 23:19:32 Elie Morisse via Digitalmars-d-learn wrote:
>> On Saturday, 13 October 2012 at 22:58:56 UTC, Timon Gehr wrote:
>> > Afaik free-function operator overloads (but not in the context of UFCS) were considered and turned down because D did not want to get amidst discussions about adding Koenig lookup. UFCS does not do Koenig lookup.
>>
>> I don't get it, aren't the current symbol lookup rules enough to make free function operator overloads useful? To me it looks like they are.
>>
>> Sorry for digging up this thread, just getting irritated by a restriction that seems pointless and arbitrary.
>>
>> Overloaded operators would suffer from the same potential abuses other methods are subjected to if UFCS was enabled, nothing more as far as I can see.
>
> If UFCS doesn't work, because there are two free functions with the same name which take the same arguments, then you can differentiate between them by not using UFCS and using their full import paths, or you can alias them so that they don't have the same name. Neither of those would be possible with operator overloading. If overloaded operators were allowed as free functions, then if there were ever a symbol conflict, you'd be screwed.
>
> - Jonathan M Davis

  X.FreeFunc(Y); // multiple matches error
  ModuleA.FreeFunc(X, Y); // ok

  X * Y; // multiple matches error
  ModuleA.opBinary!'*'(X, Y); // ok

Is there much of a difference between the two?
May 25, 2016
On Wednesday, May 25, 2016 15:46:23 Elie Morisse via Digitalmars-d-learn wrote:
> On Tuesday, 24 May 2016 at 23:43:46 UTC, Jonathan M Davis wrote:
> > On Tuesday, May 24, 2016 23:19:32 Elie Morisse via
> >
> > Digitalmars-d-learn wrote:
> >> On Saturday, 13 October 2012 at 22:58:56 UTC, Timon Gehr wrote:
> >> > Afaik free-function operator overloads (but not in the context of UFCS) were considered and turned down because D did not want to get amidst discussions about adding Koenig lookup. UFCS does not do Koenig lookup.
> >>
> >> I don't get it, aren't the current symbol lookup rules enough to make free function operator overloads useful? To me it looks like they are.
> >>
> >> Sorry for digging up this thread, just getting irritated by a restriction that seems pointless and arbitrary.
> >>
> >> Overloaded operators would suffer from the same potential abuses other methods are subjected to if UFCS was enabled, nothing more as far as I can see.
> >
> > If UFCS doesn't work, because there are two free functions with the same name which take the same arguments, then you can differentiate between them by not using UFCS and using their full import paths, or you can alias them so that they don't have the same name. Neither of those would be possible with operator overloading. If overloaded operators were allowed as free functions, then if there were ever a symbol conflict, you'd be screwed.
> >
> > - Jonathan M Davis
>
>    X.FreeFunc(Y); // multiple matches error
>    ModuleA.FreeFunc(X, Y); // ok
>
>    X * Y; // multiple matches error
>    ModuleA.opBinary!'*'(X, Y); // ok
>
> Is there much of a difference between the two?

It's not an overloaded operator anymore at that point, and that definitely fails to work for generic code, since not all operators are overloaded operators. Free functions don't have that problem.

- Jonathan M Davis

May 25, 2016
On Wednesday, 25 May 2016 at 21:50:06 UTC, Jonathan M Davis wrote:
> It's not an overloaded operator anymore at that point, and that definitely fails to work for generic code, since not all operators are overloaded operators. Free functions don't have that problem.

Sorry to reiterate the previous post but is that really the case?

  void FuncTemplate(...)(...) {
    X.FreeFunc(Y);
  }

  import ModuleA; // contains FreeFunc
  import ModuleB; // contains a conflicting FreeFunc overload

  FuncTemplate!()(); // fails

Where is the difference with writing generic code with operators (overloaded or not)?
May 25, 2016
On Wednesday, May 25, 2016 23:31:18 Elie Morisse via Digitalmars-d-learn wrote:
> On Wednesday, 25 May 2016 at 21:50:06 UTC, Jonathan M Davis wrote:
> > It's not an overloaded operator anymore at that point, and that definitely fails to work for generic code, since not all operators are overloaded operators. Free functions don't have that problem.
>
> Sorry to reiterate the previous post but is that really the case?
>
>    void FuncTemplate(...)(...) {
>      X.FreeFunc(Y);
>    }
>
>    import ModuleA; // contains FreeFunc
>    import ModuleB; // contains a conflicting FreeFunc overload
>
>    FuncTemplate!()(); // fails
>
> Where is the difference with writing generic code with operators
> (overloaded or not)?

The difference is that it's impossible to do 10.opBinary!"+"(15), so if you're forced to do foo.opBinary!"+"(bar) to get around a symbol conflict, it won't work with built-in types. UFCS does not have that problem, because you're dealing with free functions and can choose to not use UFCS and provide the full import path or to alias the function, which you can't do with operators - particularly built-in operators.

D was designed to be much cleaner with operator overloading than C++ is. It restricts what the definitions of the operators are so that you don't have to define as many of them to get the basic operations (e.g. opCmp for most of the comparison operators or op!"++" for both pre-increment and post-increment) and so that they aren't easily overloaded to do stuff that does not correspond to what that operator does for built-in types. D doesn't even use + for string concatenation, because Walter thought that that was operator abuse. Allowing arbitrary code to add overloaded operators to an existing type is not at all in line with that philosophy.

Regardless, there really isn't much point in arguing this. If you want things to change, you're going to need to convince Walter, which I very much doubt is going to happen.

- Jonathan M Davis

May 26, 2016
On Thursday, 26 May 2016 at 06:23:17 UTC, Jonathan M Davis wrote:
> The difference is that it's impossible to do 10.opBinary!"+"(15), so if you're forced to do foo.opBinary!"+"(bar) to get around a symbol conflict, it won't work with built-in types.

Obviously operator overloading should be limited to class and struct types, so that's not really relevant.

> UFCS does not have that problem, because you're dealing with free functions and can choose to not use UFCS and provide the full import path or to alias the function, which you can't do with operators - particularly built-in operators.

I still don't understand what you're getting at, unfortunately.

> D was designed to be much cleaner with operator overloading than C++ is. It restricts what the definitions of the operators are so that you don't have to define as many of them to get the basic operations (e.g. opCmp for most of the comparison operators or op!"++" for both pre-increment and post-increment) and so that they aren't easily overloaded to do stuff that does not correspond to what that operator does for built-in types. D doesn't even use + for string concatenation, because Walter thought that that was operator abuse. Allowing arbitrary code to add overloaded operators to an existing type is not at all in line with that philosophy.
>
> Regardless, there really isn't much point in arguing this. If you want things to change, you're going to need to convince Walter, which I very much doubt is going to happen.
>
> - Jonathan M Davis

Thanks for taking the time to explain, although I still fail to see a good justification for disabling UFCS for operators. I will look for more discussions on the topic and if still no opposing argument seems valid I might push the issue forward.
May 26, 2016
On Thursday, May 26, 2016 16:24:37 Elie Morisse via Digitalmars-d-learn wrote:
> On Thursday, 26 May 2016 at 06:23:17 UTC, Jonathan M Davis wrote:
> > The difference is that it's impossible to do
> > 10.opBinary!"+"(15), so if you're forced to do
> > foo.opBinary!"+"(bar) to get around a symbol conflict, it won't
> > work with built-in types.
>
> Obviously operator overloading should be limited to class and struct types, so that's not really relevant.

It's completely relevent, because generic code is frequently going to operate on a variety of types - including both built-in types and user-defined types. If code is going to use +, then + must work. opBinary!"+" is simply not going to cut it. With UFCS, if there's a potential symbol conflict, then you can work around it - even in generic code. But with an overloaded operator, the operator must work as an operator, or generic code simply won't work.

> > UFCS does not have that problem, because you're dealing with free functions and can choose to not use UFCS and provide the full import path or to alias the function, which you can't do with operators - particularly built-in operators.
>
> I still don't understand what you're getting at, unfortunately.

You don't _have_ to use UFCS. You can call the function as a normal free
function with the full import path. You can also alias the function to a
different name and use that with UFCS or import the conflicting function
with an alias so that it doesn't conflict. The overloaded operator, on the
other hand, needs to work as on overloaded operator, and we can't just call
an overloaded operator with its full import path or alias it when
importing it, because it's an overloaded operator and not just a free
function. We have ways to distinguish conflicting types with free functions,
and we don't with operators, because operators were designed to be part of
the type and not free functions. And syntactically, it really doesn't work
to provide a way to distinguish between conflicting versions of an
overloaded operator, because then you're no longer just using the operator
and might as well just be using a function.

But all I'm really doing here is saying the same thing multiple times in slightly different ways, so if you don't get it, I don't know how to explain it.

> Thanks for taking the time to explain, although I still fail to see a good justification for disabling UFCS for operators. I will look for more discussions on the topic and if still no opposing argument seems valid I might push the issue forward.

You're going to need more than a good reason why it shouldn't be allowed. You're going to need a good reason why it should be, and I really don't think that you're going to have one good enough to get you anywhere with Walter. I'm fairly certain that there's a thread or two floating around somewhere in the main newsgroup where he's responded to the issue before though.

- Jonathan M Davis