September 03, 2016
On 3 September 2016 at 11:25, Walter Bright via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
> On 9/2/2016 6:12 PM, Stefan Koch wrote:
>>
>> If this feature were supported, it would probably break our module system. Even if we could shoehorn it into the language it would make the compiler slower.
>
>
> Note that C++ needs ADL in part because it cannot do options 2, 3 or 4.

They're not solutions though, they're workarounds. They're all
problematic, and highly unsavoury.
Nobody is gonna go "oh, i really wish i could do those things in
C++!", because the problem is already solved :/
September 03, 2016
On Friday, 2 September 2016 at 23:51:35 UTC, Manu wrote:
> This pattern seems to bite me every direction I turn when trying to
> write range or algorithm style code. C++ has ADL, and ADL works. I've
> never thought about this problem in C++, or had any problems with ADL.

IMO the root of this problem is that templates are *duck typed*. All those problems wouldn't even exist with concepts/traits/typeclasses (done right).
ADL is only an ugly hack.

And with "Design by Introspection" it only gets worse: If an optional operation exists, but is not found because of unexpected problems like these, it still compiles but you only get limited functionality or bad performance.
September 03, 2016
On 9/2/2016 9:14 PM, Manu via Digitalmars-d wrote:
> They're not solutions though, they're workarounds. They're all
> problematic, and highly unsavoury.

What makes them problematic or highly unsavory? I thought #4 in particular was rather cool, I plan to use it as an example.


> Nobody is gonna go "oh, i really wish i could do those things in
> C++!", because the problem is already solved :/

ADL has the problems I provided a link to.

In any case, these difficulties are the consequence of trying to write C++ code in D. None of the algorithms used in std.algorithm or elsewhere in Phobos have this particular issue. Nor have I seen ADL supported in any other language, despite many supporting generic algorithms.

I do understand trying to write C++ code in D, because my early FORTRAN programs looked like BASIC, my early C programs looked like FORTRAN, my C++ code looked like C, etc.

What I have provided is a generic way to make ADL work in D, which shows how adaptable it is.
September 03, 2016
On 9/3/2016 1:37 AM, Walter Bright wrote:
> I thought #4 in particular was rather cool, I plan to use it as an example.

https://github.com/dlang/phobos/pull/4762

September 03, 2016
On 3 September 2016 at 11:09, Walter Bright via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>
> First solution:
>
>    module bob;
>    struct S {
>        void f();
>    }

This is my current workaround.
I'm not happy with it at all. UFCS exists for a reason.


> Second solution:
>
>     module user_code;
>     import bob, joe;
>     import myalgorithm;
>
>     mixin myalgorithm.test!S;
>     mixin myalgorithm.test!T;
>
>     void main()
>     {
>       test(S.init);
>       test(T.init);
>     }

You're not serious, right?
I just want to call a function... functions should be functions, not
mixin templates!


> Third solution:
>
>     module myalgorithm;
>     void test(M,T)(T t)
>     {
>         M.f(t);
>     }
>
>     module user_code;
>     import bob, joe;
>     import myalgorithm;
>
>     void main()
>     {
>       test!bob(S.init);
>       test!joe(T.init);
>     }

Another crazy workaround.
Users should not be expected to manually pass scope's around the place
to perform a name lookup.
Try and explain that to a normal programmer.


> Fourth solution:
>
>     module myalgorithm;
>
>     void test(T)(T t)
>     {
>         import std.traits;
>         mixin("import " ~ std.traits.moduleName!T ~ ";");
>         mixin("alias M = " ~ std.traits.moduleName!T ~ ";");
>         // The above could be encapsulated into an eponymous template
>         // that takes T as a parameter and returns the alias
>
>         M.f(t);
>     }
>
> What makes them problematic or highly unsavory? I thought #4 in particular was rather cool, I plan to use it as an example.

I also had this idea as workaround, but you can't seriously think this is okay?
Importing an entire module at the point I want to call a function is crazy.
I don't want to import _everything_ from T's module into my local
namespace; that could easily lead to conflicting names in the local
scope which would now require disambiguation.
This surely represents a far higher probability of name collisions
than the theoretical accidental collision that could come from ADL.
The ADL style collision isn't accidental though, that's _the whole point_.


>> or had any problems with ADL
>
>     https://en.wikipedia.org/wiki/Argument-dependent_name_lookup#Criticism
>
> Essentially, ADL has awkward problems when getting beyond the simple cases. It isn't right for D.

D requires ADL so much more than C++ does, because the things ADL does in C++ are absolute concrete advertised core value propositions of D.


> ADL has the problems I provided a link to.

It's never caused me a problem, in like, 15 years or more. This situation in D causes me problems all the time.


> In any case, these difficulties are the consequence of trying to write C++ code in D.

You've told me this before, and I find it kind of offensive every time
you do, since I've been programming D for like 7 years now, and I
definitely don't code D like C++.
If anything, I have a strong tendency to code C++ like D, and that has
lead to a lot of interesting changes in my C++ style.

I'm tired of these sorts of dismissals. You insist that I'm not a 'real' D programmer, or something to that effect.

This problem consistently arises when I try to commit to go all in on ranges+UFCS pipeline style programming. There's nothing C++-ey about that. C++ can barely do it. It is the advertised mission of modern D programmers to write code this way, and it's the exact area where the problem I'm trying to express breaks down.

The interesting part is, when I do try and code this way in C++ (which is brutal, it's all SFINAE based template constraints and stuff), it actually _works_, simply because ADL works.

Pipeline programming is a core value proposition for D, as are uber-powerful templates which leads to making algorithms out of everything.


> None of the algorithms used in std.algorithm or elsewhere in
> Phobos have this particular issue. Nor have I seen ADL supported in any
> other language, despite many supporting generic algorithms.

std.algorithm is extremely simple, it doesn't do anything except raw algorithm-ey stuff. It doesn't attempt to invoke functionality on the data it's working on.

Right now I'm working on image processing. There are lots of image
data types, and they all have things like interpolation and blending
functions. Write an image processing algorithm that calls out to lerp
or blend, and you'll run into these problems instantly.
I was writing some audio software some time back, again, trying to use
stream processing extensively because it's a perfect match for that
workload, but same problem!

Write an algorithm that does _work_, rather than does algorithm logic, and you can't miss this problem. You need to call associated functions to do work.


> I do understand trying to write C++ code in D, because my early FORTRAN programs looked like BASIC, my early C programs looked like FORTRAN, my C++ code looked like C, etc.

Again, stop this. It's insulting, and it really pisses me off.
I'm writing textbook modern D, which is code that you can't even express in C++.


> What I have provided is a generic way to make ADL work in D, which shows how adaptable it is.

I never said D wasn't adaptable and capable of madhax. I understand
very well that D is powerful enough to find a possible work-around for
basically anything. You wouldn't believe some of the hacks I'm
responsible for! (mostly relating to ref! >_<)
It's useful once in a while, but once some particular hax present
themselves as rule rather than the excepsion, you find yourself
effectively engaged in writing boilerplate. Just like C, but a
different kind of boilerplate, and for my money; extremely more
complex boilerplate than C/C++, which only experts can read and
understand. I am absolutely not okay with that sort of madhax.
September 03, 2016
On 3 September 2016 at 18:56, Walter Bright via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
> On 9/3/2016 1:37 AM, Walter Bright wrote:
>>
>> I thought #4 in particular was rather cool, I plan to use it as an example.
>
>
> https://github.com/dlang/phobos/pull/4762

Complexity ramps up further if there are N arguments to the algorithm. It needs to search each of the arguments modules.
September 03, 2016
On 03.09.2016 11:37, Manu via Digitalmars-d wrote:
> On 3 September 2016 at 18:56, Walter Bright via Digitalmars-d
> <digitalmars-d@puremagic.com> wrote:
>> On 9/3/2016 1:37 AM, Walter Bright wrote:
>>>
>>> I thought #4 in particular was rather cool, I plan to use it as an
>>> example.
>>
>>
>> https://github.com/dlang/phobos/pull/4762
>
> Complexity ramps up further if there are N arguments to the algorithm.
> It needs to search each of the arguments modules.
>

template adl(string fun){ /* TODO */ }

adl!"foo"(S.init,T.init);
September 03, 2016
On 03.09.2016 03:12, Stefan Koch wrote:
> On Saturday, 3 September 2016 at 01:09:18 UTC, Walter Bright wrote:
>>
>> Essentially, ADL has awkward problems when getting beyond the simple
>> cases. It isn't right for D.
>
> I could not agree more strongly!
>
> If this feature were supported, it would probably break our module system.

Break how?

> Even if we could shoehorn it into the language it would make the
> compiler slower.

If ADL is done as a fallback, then it is only slower in those cases where it is either actually used, or __traits(compiles,...) is used to determine that some function overload does not exist.
September 03, 2016
On 9/3/2016 2:37 AM, Manu via Digitalmars-d wrote:
> On 3 September 2016 at 18:56, Walter Bright via Digitalmars-d
> <digitalmars-d@puremagic.com> wrote:
>> On 9/3/2016 1:37 AM, Walter Bright wrote:
>>>
>>> I thought #4 in particular was rather cool, I plan to use it as an
>>> example.
>>
>>
>> https://github.com/dlang/phobos/pull/4762
> Complexity ramps up further if there are N arguments to the algorithm.
> It needs to search each of the arguments modules.

I suggest posting the actual problems you're having, because twice now you've gotten solutions to the problems you posted, then said they weren't your actual problems.


This template:

// Find module in which T was defined
template ModuleOf(alias T)
{
    import std.traits : moduleName;
    mixin("import " ~ moduleName!T ~ ";");
    mixin("alias ModuleOf = " ~ moduleName!T ~ ";");
}

can be used to qualify any function with the module in which one expects to find it.


> Complexity ramps up further if there are N arguments to the algorithm.
> It needs to search each of the arguments modules.

Bluntly, if a library is designed around multi-argument ADL as a core requirement, redesign it. I.e. the same advice as for multiple inheritance. It's just not worth it.

If you are still determined to use it, you can use:

   __traits(compiles, ...)

like you would SFINAE in C++ to select which of the modules from the argument types selects a function that compiles.

September 03, 2016
On 03.09.2016 10:37, Walter Bright wrote:
> None of the algorithms used in std.algorithm or elsewhere in Phobos have
> this particular issue.

Yes they do. It is not possible to implement the range functions as non-members.


> Nor have I seen ADL supported in any other
> language, despite many supporting generic algorithms.

Which other such languages have templates like D or C++?