September 03, 2016
On 9/3/2016 9:01 AM, Manu via Digitalmars-d wrote:
> Right, and it also has to not conflict with possible local
> definitions, or instances supplied by imports in the local namespace.
> Ie, the module where T came from is *an additional* place to look, not
> *the* place to look.
> I expect that local definitions may exist for things like generic
> fallbacks, or primitive/builtin type implementations.

1. 'alias func = ...;' also works to bring in local definitions to an even footing with the other alias func statements.

2. Due to recent changes to import lookup rules, imports are searched if locals do not satisfy the lookup.

3. You can use traits(compiles, ...) to not insert the names in the local scope if it already can be looked up.

So I believe you're good to go.
September 03, 2016
On 9/3/16 10:29 PM, Walter Bright wrote:
> On 9/3/2016 6:04 AM, Andrei Alexandrescu wrote:
>> This only works with the respective modules do define `func`. We need
>> something
>> that conditionally plants the symbol depending on whether the module
>> defines it
>> or not. -- Andrei
>
>
> That's where __traits(compiles, ...) comes in. It can be encapsulated in
> another template.

Yah. That we need to plant in the standard library. -- Andrei

September 03, 2016
On 9/3/2016 8:34 AM, Manu via Digitalmars-d wrote:
> And if either module doesn't have an instance of func?

static if (traits(compiles, ModuleOf!T.func))
    alias func = ModuleOf!T.func;
September 03, 2016
On 9/3/16 10:43 PM, Walter Bright wrote:
> On 9/3/2016 8:34 AM, Manu via Digitalmars-d wrote:
>> And if either module doesn't have an instance of func?
>
> static if (traits(compiles, ModuleOf!T.func))
>     alias func = ModuleOf!T.func;

What's an elegant way to encapsulate this as a stutter-free one-liner? -- Andrei
September 03, 2016
On 9/3/2016 8:51 AM, Manu via Digitalmars-d wrote:
> This is exactly the difference between std.algorithm, and what I was
> trying to express as an algorithm that 'does work'. It's not the
> business of the API for the user to supply the work to do (ie, via
> lambda); the function is meant to do the work, which means it needs to
> call other functions. There are no lambdas to be seen in this
> situation.

This is purely a stylistic issue. I, on the other hand, think lambdas are a superior design, as ADL lookups never sat well with me because it can be quite difficult for the user to figure out where 'func' is coming from.


>> (Besides, I showed how other scopes can be imported based on a type, and
>> then things can be looked up in those scopes, and UFCS applied.)
> I still think that's unnecessarily complicated, and multiple arguments
> leads to static if-ing and __traits(compiles,...). The fact the user
> needs to intervene at all is already too much.

I already showed how your previous objection to this could be folded away inside a nice template.


> Apparently I need to stress again, this is a *core value proposition
> of D*... It's presented as "this is modern D code", and yet it's
> awkward and requires careful handling or you get hard to understand
> name-resolution issues.

As mentioned, I don't see anything hard to understand about it - it makes it clear to the reader where names are coming from. ADL pulls names in from who knows where.


> UFCS *is* modern D. Algorithms and ranges *is* modern D.
> Seriously, this is the style that modern D aspires to, and it doesn't
> 'just work'. There should be ear-piercing alarms and flashing red
> everywhere.
> This comes up for me frequently, yet ADL has never caused me a single
> moments trouble, in 15+ years. I didn't even know ADL existed until I
> started running into this problem in D and then wondered to myself why
> I never encountered the same issue in C++. It worked so seamlessly and
> intuitively, I didn't even know it was there.
>
> I don't care if the solution is ADL like C++, or something else that
> works, just that this problem is real; it's a massive fly in the
> ointment of modern D style, and I don't think it's acceptable. It
> needs a seamless solution, not manual intervention at every case. D
> depends on this so much more than C++ does.

You've used ADL for 15 years. You're obviously very comfortable with it. I suggest trying out using lambdas enough to feel comfortable with it before deciding that ADL is better. New coding styles are rarely comfortable right off the bat.

September 03, 2016
On 9/3/2016 9:24 AM, Andrei Alexandrescu wrote:
> On 9/3/16 5:57 PM, Manu via Digitalmars-d wrote:
>> It's not a problem I've ever had.
> A problem you didn't know you have. It's a classic C++ conundrum combining
> theory and practice.


One thing I've noticed in my years of programming and helping others with their code is that one can use a feature for decades, over and over, but are only using it in a certain specific way. One is lulled into thinking that it works in the general case because one is not aware that one's usage is constrained.

Someone else comes along, uses it slightly differently, and oops.

"But I always took the left fork!" :-)

It bites me all the time.
September 03, 2016
On 9/3/2016 6:22 AM, ZombineDev wrote:
> I agree that it's not a template issue. It's more of a modules vs namespaces
> issue. I think the lack of ADL is not a problem in C# because everyone can (and
> everyone does) extend an existing namespace, so most user's of LINQ algorithms
> just slap a `using System.Linq` on top of the file without caring in exactly
> which file the functionality they're using is coming from.

Hmm, that explanation could be it. I'm not very familiar with LINQ.
September 03, 2016
On 9/3/16 11:31 AM, Manu via Digitalmars-d wrote:
>> > 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.

There's really no need to take offense here. We have a bit of a mimosa culture of easily bruised egos it seems. As the joke goes: "You take offense too easily." "I can't believe you just said that!"

It's hard to not see your view as coming straight from the "I want to speak Italian by replacing English words with Italian words" box.

* It hypothesizes that one entire style of design is completely impossible because it lacks one obscure feature from C++.

* Vast evidence to the contrary is ignored.

* The fact that the feature is problematic and controversial even within C++ circles is also neglected.

* The lack of said feature is regarded as an utter disaster and no workaround is even close to cutting the mustard.

* A language change is a must; no library solution would ever be acceptable.

For the most part this is a Pop a level up and figure what the needed accomplishment is, so other routes than the ADL bottleneck are possible. Let's approach this together like a problem that has a solution within D, and let's make that solution accessible comfortably.

Two apocryphal anecdotes: Koenig invented the eponymous lookup as a consequence to the fact that namespaces broke the "Hello, world" program (something to do with cout and endl being migrated to namespace std), which surprised the inner circles of C++ the way putting mentos in coke surprises the unwary. Namespaces are an unusually poorly designed feature of C++, not second even to exceptions. By that time significant work had been invested in defining and implementing namespaces, so going back wasn't quite an option. ADL was hailed as a horrible hack but a lifesaving one. Compilers have been slow to implement ADL, partly because essentially it meant breaking a lookup algorithm that was relatively orderly and DWIM, and replace it with a patchwork of special cases. The community has since learned to live with the odd idioms that make code work with the new rules.

Second anecdote: Scott Meyers had an infamous talk on C++ in which the leitmotif was "What does f(x) mean?" Scott asks the question in the beginning to which the obvious response is "Call function f passing it argument x". By the time his talk is done, the horrified audience realizes they have no idea what f(x) means and where it goes.


Andrei

September 03, 2016
On 9/3/2016 1:43 PM, Andrei Alexandrescu wrote:
> On 9/3/16 10:43 PM, Walter Bright wrote:
>> On 9/3/2016 8:34 AM, Manu via Digitalmars-d wrote:
>>> And if either module doesn't have an instance of func?
>>
>> static if (traits(compiles, ModuleOf!T.func))
>>     alias func = ModuleOf!T.func;
>
> What's an elegant way to encapsulate this as a stutter-free one-liner? -- Andrei

using a template and mixing it in
September 03, 2016
On 9/3/2016 3:35 AM, Walter Bright wrote:
> That isn't how it works in C++. It's done right up front in finding the
> candidates for overloading, not as a fallback.

That statement is incorrect. It's used as a fallback in C++. I had forgotten.