September 28, 2017
On 27 September 2017 at 22:01, jmh530 via Digitalmars-d < digitalmars-d@puremagic.com> wrote:

> On Wednesday, 27 September 2017 at 07:41:23 UTC, Ilya Yaroshenko wrote:
>
>>
>> I would prefer outer operator overloading be added to D instead of type wrappers. So a user can import a library for operations, rather then library of wrappers. --Ilya
>>
>
> This might be a step in the right direction. It doesn't need to be full-blown extension methods/partial classes. Just the ability to treat operator overloading like free-standing functions (with power of UFCS). Something like:
>
> struct Foo
> {
>     int data;
> }
>
> Foo opBinary!(string op)(Foo x, Foo y)
> {
>     return mixin("x.data" ~ op ~ "y.data");
> }
>
> That would mean you could also do something like:
> import lubeck : opBinary;
>

Again, sadly, D has no ADL, and this will be an unmitigated disaster as a
result!
Instantiations of templates will use the default elementwise operator
instead of the one you specified in your module, and nobody will understand
why.


September 28, 2017
On Wednesday, 27 September 2017 at 23:25:34 UTC, Manu wrote:
>
> Again, sadly, D has no ADL, and this will be an unmitigated disaster as a
> result!
> Instantiations of templates will use the default elementwise operator
> instead of the one you specified in your module, and nobody will understand
> why.

Argument-dependent lookup? I'm not an expert on C++, but I read the wikipedia entry on it. It does seem like an issue worth thinking more about

One (hacky) solution is to not have default implementations for the all the operators (the focus so far has been on the multiple uses of * for element-wise multiply and dot product/matrix multiplication). So you have Slice in mir.ndslice.slice. Then make a mir.ndslice.operator.elementwise module that has the operator overloading for elementwise operations, then a module mir.ndslice.operator.linalg (or somewhere in lubeck) with the dot product or inverse implementations. The key to making this work is that you also need a mid.ndslice.arithmetic or something that allows the user to call these functions without operator overloading. This way they can put import their default, but if they have a function that mixes and matches dot and element-wise multiplication, they can do that too.
September 27, 2017
On 9/27/2017 4:21 PM, Manu wrote:
> D does not have ADL,

Thank gawd! :-)

> which will almost certainly lead to _very_ nasty surprises in behaviour.

ADL was always a hack to get around the wretched overloading symbol lookup behavior in C++. I see it has somehow morphed into a feature :-( but I see no advantage to it over D's approach (the reverse operand lookup scheme).

September 28, 2017
On Thursday, 28 September 2017 at 01:58:24 UTC, Walter Bright wrote:
> ADL was always a hack to get around the wretched overloading symbol lookup behavior in C++.

Any sufficiently advanced bug is indistinguishable from a feature! ;)

-Wyatt
September 30, 2017
On 28 September 2017 at 11:58, Walter Bright via Digitalmars-d < digitalmars-d@puremagic.com> wrote:

> On 9/27/2017 4:21 PM, Manu wrote:
>
>> D does not have ADL,
>>
>
> Thank gawd! :-)
>
> which will almost certainly lead to _very_ nasty surprises in behaviour.
>>
>
> ADL was always a hack to get around the wretched overloading symbol lookup behavior in C++. I see it has somehow morphed into a feature :-( but I see no advantage to it over D's approach (the reverse operand lookup scheme).
>

Whether you like it or not, the lack of ADL will make the idea of operator overloading a disaster.

Don't get me wrong, I'm not married to ADL, I'm completely ambivalent on
its design. As I see, it just makes a fairly important set of problems work
in a predictable and useful manner, and I haven't encountered issues with
it before.
The problem is, D offers no solution to the important issues that ADL
addresses, and I think that's a much worse situation than the existence of
ADL.


September 30, 2017
On 9/29/2017 7:17 PM, Manu wrote:
> Whether you like it or not, the lack of ADL will make the idea of operator overloading a disaster.

Please present an example.
September 30, 2017
On 9/28/2017 7:42 AM, Wyatt wrote:
> Any sufficiently advanced bug is indistinguishable from a feature! ;)

D has other ways of doing what ADL does, so I am curious for an example from Manu about why it doesn't work.
October 02, 2017
On 30.09.2017 23:45, Walter Bright wrote:
> ...
> D has other ways of doing what ADL does,

What are those ways? I'm aware of two basic strategies, both suboptimal:

- Every module imports all other modules.
- Proliferation of wrapper types.

> so I am curious for an example from Manu about why it doesn't work.

It's not per se related to operator overloading:

---
module a;
import std.range: isInputRange;
auto sum(R)(R r)if(isInputRange!R){
    typeof(r.front) result;
    for(auto t=r.save;!t.empty;t.popFront())
        result+=t.front;
    return result;
}
---

---
module b;
import a;
import std.range;

void main(){
    int[] a = [1,2,3,4];
    import std.stdio: writeln;
    writeln(a.front); // ok
    writeln(sum(a)); // error, the type is an input range, yet has no front
}
---

I.e., the operations that are supported on the type differ depending on the module that it is accessed from. If there are multiple definitions of the same name, different modules might not agree which one is being referred to. (This is particularly likely for overloaded operators, as the set of names is finite and small. This is what Manu means when he says it can lead to nasty surprises. This is very plausible, but I don't have a good example.)
October 03, 2017
On Thursday, 28 September 2017 at 01:58:24 UTC, Walter Bright wrote:
> On 9/27/2017 4:21 PM, Manu wrote:
> [...]
> but I see no advantage to it over D's approach (the reverse operand lookup scheme).

I couldn't find anything focused on D's overloading resolution scheme (or anything with the specific term "reverse operand lookup"). Can you elaborate?
October 03, 2017
On 10/2/2017 4:15 AM, Timon Gehr wrote:
> On 30.09.2017 23:45, Walter Bright wrote:
>> ...
>> D has other ways of doing what ADL does,
> 
> What are those ways? I'm aware of two basic strategies, both suboptimal:
> 
> - Every module imports all other modules.
> - Proliferation of wrapper types.

https://dlang.org/spec/operatoroverloading.html#binary

C++ does not have this notion.


> It's not per se related to operator overloading:

ADL was specifically intended to address operator overloading.


> ---
> module a;
> import std.range: isInputRange;
> auto sum(R)(R r)if(isInputRange!R){
>      typeof(r.front) result;
>      for(auto t=r.save;!t.empty;t.popFront())
>          result+=t.front;
>      return result;
> }
> ---
> 
> ---
> module b;
> import a;
> import std.range;
> 
> void main(){
>      int[] a = [1,2,3,4];
>      import std.stdio: writeln;
>      writeln(a.front); // ok
>      writeln(sum(a)); // error, the type is an input range, yet has no front
> }
> ---
> 
> I.e., the operations that are supported on the type differ depending on the module that it is accessed from. If there are multiple definitions of the same name, different modules might not agree which one is being referred to. (This is particularly likely for overloaded operators, as the set of names is finite and small. This is what Manu means when he says it can lead to nasty surprises. This is very plausible, but I don't have a good example.)

This gets into the anti-hijacking support D has (and C++ does not). If multiple modules with declarations of `writeln` are in scope, the compiler attempts a match with `writeln` in each module. If there is a match with more than one module, an error is issued. The user will then have to specify which one he wants.

This is specifically designed to prevent nasty surprises. C++ has a big problem with ADL in that overloading is not encapsulated and any #included header can inadvertently add more overloads that may be entirely unrelated. Any .h can crack open any namespace and insert more overloads into it. It's completely unhygienic and uncontrollable.

As for the specific example you gave, I get:

a.d(3): Error: no property 'front' for type 'int[]'
a.d(4): Error: no property 'save' for type 'int[]'
b.d(8): Error: template instance a.sum!(int[]) error instantiating