September 03, 2016
On Saturday, 3 September 2016 at 16:32:16 UTC, ZombineDev wrote:
> No you're wrong. There's no need for interfaces or for generic constraints. It's not static vs duck typing. It's just a method lookup issue. See for yourself: http://rextester.com/GFKNSK99121

Ok, Interfaces and other generic methods with compatible constraints.
But in the end you cannot do much without any interface constraints except writing out to the console as you do in the example.

But the main point still holds, name lookup is only done at definition time, not at instantiation time. That's why you can only call generic methods. Overloads don't work.

> Sum is implemented in that stupid way, because unlike C++, in C# operators need to be implemented as static methods, so you can't abstract them with an interface. If they were instance methods, you could implement them outside of the class as extension methods and there would be no need to write a distinct method for each type. Here's an example: http://rextester.com/PQFPC46087
> The only thing missing is syntax sugar to forward the '+' operator to 'Add' in my example.

With runtime reflection you can do almost anything... That's circumventing the type system and doesn't disprove anything.
I mean, it even "works" for types that cannot be added at all, by just returning a default value...
September 03, 2016
On Saturday, 3 September 2016 at 16:33:07 UTC, Andrei Alexandrescu wrote:
> I see. This is a matter orthogonal to DbI - introspection should be able to figure out whether a member can be found, or a nonmember if the design asks for it. I wouldn't like "tricking" DbI into thinking a member is there when there isn't. -- Andrei

The problem I see with DbI is rather that the user of a function thinks that an optional constraint is satisfied, while in reality it isn't, due to a non-obvious lookup/visibility problem.
September 03, 2016
Tobias M <troplin@bluewin.ch> wrote:
> On Saturday, 3 September 2016 at 16:32:16 UTC, ZombineDev wrote:
>> Sum is implemented in that stupid way, because unlike C++, in
>> C# operators need to be implemented as static methods, so you
>> can't abstract them with an interface. If they were instance
>> methods, you could implement them outside of the class as
>> extension methods and there would be no need to write a
>> distinct method for each type. Here's an example:
>> http://rextester.com/PQFPC46087
>> The only thing missing is syntax sugar to forward the '+'
>> operator to 'Add' in my example.
> 
> With runtime reflection you can do almost anything... That's
> circumventing the type system and doesn't disprove anything.
> I mean, it even "works" for types that cannot be added at all, by
> just returning a default value...

It's not runtime reflection, sorry about that.

But Add claims to be generic but it's actually just a list of special
cases.
It compiles for all types but only works for some. And even worse,
for types that actually do support addition but are not in the list it
silently does the wrong thing.

You cannot do the same in a truly generic way.


September 03, 2016
On 9/3/16 7:00 PM, vit wrote:
> On Saturday, 3 September 2016 at 13:04:30 UTC, Andrei Alexandrescu wrote:
>> On 9/3/16 1:24 PM, Walter Bright wrote:
>>> On 9/3/2016 3:12 AM, Walter Bright wrote:
>>>> 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.
>>>
>>> Eh, I realized it's simpler than that. Based on the code I already
>>> presented, each argument can be used to generate an import for its
>>> corresponding version of the function. Then, overloading rules apply and
>>> it works. Something like:
>>>
>>> Something like:
>>>
>>> void foo(T,U)(T t, U u)
>>> {
>>>     alias func = ModuleOf!T.func;
>>>     alias func = ModuleOf!U.func;
>>>
>>>     func(t, u);
>>> }
>>
>> 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
>
>
> perhaps this:
>
> auto adl(string fn, T, Args...)(auto ref T x, auto ref Args args)

Perhaps too surgical (although nice to have as an option). We need something that pulls the symbol for all purposes. -- Andrei

September 03, 2016
On 9/3/16 7:08 PM, Tobias M wrote:
> On Saturday, 3 September 2016 at 16:33:07 UTC, Andrei Alexandrescu wrote:
>> I see. This is a matter orthogonal to DbI - introspection should be
>> able to figure out whether a member can be found, or a nonmember if
>> the design asks for it. I wouldn't like "tricking" DbI into thinking a
>> member is there when there isn't. -- Andrei
>
> The problem I see with DbI is rather that the user of a function thinks
> that an optional constraint is satisfied, while in reality it isn't, due
> to a non-obvious lookup/visibility problem.

At some point there's a need to RTFM. -- Andrei
September 03, 2016
Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:
> On 9/3/16 7:08 PM, Tobias M wrote:
>> On Saturday, 3 September 2016 at 16:33:07 UTC, Andrei Alexandrescu wrote:
>>> I see. This is a matter orthogonal to DbI - introspection should be able to figure out whether a member can be found, or a nonmember if the design asks for it. I wouldn't like "tricking" DbI into thinking a member is there when there isn't. -- Andrei
>> 
>> The problem I see with DbI is rather that the user of a function thinks that an optional constraint is satisfied, while in reality it isn't, due to a non-obvious lookup/visibility problem.
> 
> At some point there's a need to RTFM. -- Andrei

Is there one for DbI? (Sincere question)

September 03, 2016
On Saturday, 3 September 2016 at 17:05:35 UTC, Tobias M wrote:
> On Saturday, 3 September 2016 at 16:32:16 UTC, ZombineDev wrote:
>> No you're wrong. There's no need for interfaces or for generic constraints. It's not static vs duck typing. It's just a method lookup issue. See for yourself: http://rextester.com/GFKNSK99121
>
> Ok, Interfaces and other generic methods with compatible constraints.
> But in the end you cannot do much without any interface constraints except writing out to the console as you do in the example.
>
> But the main point still holds, name lookup is only done at definition time, not at instantiation time. That's why you can only call generic methods. Overloads don't work.

So what? C#'s generics are less flexible than C++ and D templates.
The point is that C#'s lookup does not consider only the implemented interfaces, but also falls back to extensions methods. If C# had ADL,
the compiler would also look for extension methods in the namespace
of the type (in non-generic methods, when the type is "known"), although the user of the type may not have imported the namespace.

>> Sum is implemented in that stupid way, because unlike C++, in C# operators need to be implemented as static methods, so you can't abstract them with an interface. If they were instance methods, you could implement them outside of the class as extension methods and there would be no need to write a distinct method for each type. Here's an example: http://rextester.com/PQFPC46087
>> The only thing missing is syntax sugar to forward the '+' operator to 'Add' in my example.
>
> With runtime reflection you can do almost anything... That's circumventing the type system and doesn't disprove anything.

There's no circumventing the type system. `typeof(obj)` is barely even reflection. You can do this with regular cast or using the `is` expression (http://rextester.com/CXGNK69048). I used `typeof` just because it could yield better performance.

> I mean, it even "works" for types that cannot be added at all, by just returning a default value...

? Sorry, I don't understand, what's the problem?
September 03, 2016
ZombineDev <petar.p.kirov@gmail.com> wrote:
> So what? C#'s generics are less flexible than C++ and D templates.
> The point is that C#'s lookup does not consider only the
> implemented interfaces, but also falls back to extensions
> methods. If C# had ADL,
> the compiler would also look for extension methods in the
> namespace
> of the type (in non-generic methods, when the type is "known"),
> although the user of the type may not have imported the namespace.

ADL wouldn't change anything if you don't cast to a specific type, and if you do, that part of the code is not generic anymore.

>>> Sum is implemented in that stupid way, because unlike C++, in
>>> C# operators need to be implemented as static methods, so you
>>> can't abstract them with an interface. If they were instance
>>> methods, you could implement them outside of the class as
>>> extension methods and there would be no need to write a
>>> distinct method for each type. Here's an example:
>>> http://rextester.com/PQFPC46087
>>> The only thing missing is syntax sugar to forward the '+'
>>> operator to 'Add' in my example.
>> 
>> With runtime reflection you can do almost anything... That's circumventing the type system and doesn't disprove anything.
> 
> There's no circumventing the type system. `typeof(obj)` is barely even reflection. You can do this with regular cast or using the `is` expression (http://rextester.com/CXGNK69048). I used `typeof` just because it could yield better performance.

Typecasting *is* circumventing the type system.


September 03, 2016
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.

September 03, 2016
On 9/3/16 7:38 PM, Tobias Müller wrote:
> Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:
>> On 9/3/16 7:08 PM, Tobias M wrote:
>>> On Saturday, 3 September 2016 at 16:33:07 UTC, Andrei Alexandrescu wrote:
>>>> I see. This is a matter orthogonal to DbI - introspection should be
>>>> able to figure out whether a member can be found, or a nonmember if
>>>> the design asks for it. I wouldn't like "tricking" DbI into thinking a
>>>> member is there when there isn't. -- Andrei
>>>
>>> The problem I see with DbI is rather that the user of a function thinks
>>> that an optional constraint is satisfied, while in reality it isn't, due
>>> to a non-obvious lookup/visibility problem.
>>
>> At some point there's a need to RTFM. -- Andrei
>
> Is there one for DbI? (Sincere question)

Not yet. We have the allocators body of work, but that's too niche to serve as a general example. I think std.experimental.checkedint will be the canonical example on how to do DbI. I'll propose a blog post to Mike. -- Andrei