June 17, 2019
On Sunday, 16 June 2019 at 06:08:54 UTC, Walter Bright wrote:
> On 6/15/2019 6:21 PM, Timon Gehr wrote:
>> In terms of lookup, the issues with multiple alias this are the same as the issues with multiple import declarations. Implicit conversions could use the same lookup rules, but there would need to be a way to disambiguate. The code in the compiler that implements import declarations is unlikely to be easily reusable.
>
> Multiple alias this is multiple inheritance. Generally, if you find yourself wanting multiple inheritance, it's likely time to rethink the data structures.

+1

And in D I've "needed" multiple inheritance exactly once, so I wonder what is the use case for multiple alias this...
June 17, 2019
On 6/16/2019 4:46 PM, Timon Gehr wrote:
> mixin(import("std/stdio.d"));

Template mixins are something else:

https://dlang.org/spec/template-mixin.html
June 17, 2019
On Sunday, 16 June 2019 at 09:26:21 UTC, Mike Franklin wrote:
> Contrived, naive, very incomplete illustration:
>
>     static foreach(m; __traits(allMembers, typeof(f)))
>     {
>         mixin(
>             ReturnType!(__traits(getMember, typeof(f), m)).stringof
>             ~ " " ~ m ~ "()"
>             ~ "{" ~ __traits(identifier, f) ~ "." ~ m ~ "(); }"
>         );
>     }


It has kinda become my thing to comment on this whenever I can, but that code is needlessly hideous.

1) never use .stringof to feed back to the compiler.
2) ensure all newlines inside mixin() are also inside quotes, including the one immediately after the (.
3) (almost) never use concatenation to get a member

Following those three rules simplifies that code to:

    static foreach(m; __traits(allMembers, typeof(f)))
    {
        mixin("
            ReturnType!(__traits(getMember, typeof(f), m))
            " ~ m ~ "()
            {__traits(getMember, f, m)(); }"
        );
    }

Notice the only thing concatenated is the name of the function now. So much simpler looking code, and it even works across module boundaries now.

The reasons behind each rule:

1) stringof breaks if there is another matching name in scope, or if the name in question is not in scope at all (imagine a type from a user module passed to a different library module)

2) compiler error messages from inside the mixin may have misaligned line numbers if this is broken

3) similar pitfalls to #1, including if the symbol is overloaded.

and of course, concat is ugly!


Aside from formatting, you can also go a step further in simplification and remove that std.traits entirely with an auto function:

    static foreach(m; __traits(allMembers, typeof(f)))
    {
        mixin("
            auto
            " ~ m ~ "()
            { return __traits(getMember, f, m)(); }"
        );
    }

auto functions aren't *exactly* the same... but there's several advantages here, including simpler code for return value, obviously, but also it will now inherit qualifiers from the wrapped function like @nogc, pure, etc., thanks to inference rules.
June 17, 2019
On Monday, 17 June 2019 at 13:13:07 UTC, Adam D. Ruppe wrote:
> On Sunday, 16 June 2019 at 09:26:21 UTC, Mike Franklin wrote:
>> Contrived, naive, very incomplete illustration:
>>
>>     static foreach(m; __traits(allMembers, typeof(f)))
>>     {
>>         mixin(
>>             ReturnType!(__traits(getMember, typeof(f), m)).stringof
>>             ~ " " ~ m ~ "()"
>>             ~ "{" ~ __traits(identifier, f) ~ "." ~ m ~ "(); }"
>>         );
>>     }
>
>
> It has kinda become my thing to comment on this whenever I can, but that code is needlessly hideous.

I know and thank you for posting improvements, but it was just an illustration to convey that there may be a preferred path forward for multiple alias this: implement it in the library.

So far I've only been able to find one `alias this` characteristic that can't be implemented in the library:

```
struct S
{
    int i;

    void opAssign(int v)
    {
        i = v;
    }
}

void main()
{
    S s;
    s = 1;
    int i = s;  // No way to make this work in the library.  We need `opAssignRight`.
}
```

I think if we had an `opAssignRight` feature (with friends) we could move the entire implementation of `alias this` to the library.  It would probably be a few hundred lines, but probably less than what it takes to implement in the compiler.  We could even lower the `alias field this;` expression to `mixin AliasThis!(field);` so the user wouldn't know anything happened, assuming of course that the implementation of `AliasThis` was correct.

I believe there have been 3 different PRs from the DIP66 author in the past few years attempting to implement multiple alias this, and none of them have been merged.  Now there's talk that multiple alias this shouldn't ever be implemented.  It seems to me the path forward is a pure library implementation.  And, it would be nice to delete the hundreds, if not thousands, of lines of code needed to implement `alias this` in the compiler, along with all of the bugs that accompany it.

Mike

June 17, 2019
On Monday, 17 June 2019 at 13:48:45 UTC, Mike Franklin wrote:
> On Monday, 17 June 2019 at 13:13:07 UTC, Adam D. Ruppe wrote:
>> [...]
>
> I know and thank you for posting improvements, but it was just an illustration to convey that there may be a preferred path forward for multiple alias this: implement it in the library.
>
> [...]

+1 to discuss opAssignRight

That would solve my sentinel module problem.
June 17, 2019
On Monday, 17 June 2019 at 13:48:45 UTC, Mike Franklin wrote:
> I think if we had an `opAssignRight` feature (with friends) we could move the entire implementation of `alias this` to the library. [...]
> Mike

At first glance opAssignRight is a really **brilliant** idea šŸ‘.
Why do you think that variants would be required ? i += s would work with the single op overload. Maybe it would more be something like

T opExtractRight(T){}, with T saying what type is involved in the operation

int i = s  rewritten as  int i = s.opExtractRight!int();
i += s     rewritten as  i += s.opExtractRight!int();
June 18, 2019
On 18/06/2019 3:58 AM, user1234 wrote:
> On Monday, 17 June 2019 at 13:48:45 UTC, Mike Franklin wrote:
>> I think if we had an `opAssignRight` feature (with friends) we could move the entire implementation of `alias this` to the library. [...]
>> Mike
> 
> At first glance opAssignRight is a really **brilliant** idea šŸ‘.
> Why do you think that variants would be required ? i += s would work with the single op overload. Maybe it would more be something like
> 
> T opExtractRight(T){}, with T saying what type is involved in the operation
> 
> int i = sĀ  rewritten asĀ  int i = s.opExtractRight!int();
> i += sĀ Ā Ā Ā  rewritten asĀ  i += s.opExtractRight!int();

Oh I like this.
This way it doesn't fight the other operator overloads and can be used (with them) only if they fail as-is.
June 17, 2019
On Monday, 17 June 2019 at 16:13:07 UTC, rikki cattermole wrote:
> On 18/06/2019 3:58 AM, user1234 wrote:
>> On Monday, 17 June 2019 at 13:48:45 UTC, Mike Franklin wrote:
>>> I think if we had an `opAssignRight` feature (with friends) we could move the entire implementation of `alias this` to the library. [...]
>>> Mike
>> 
>> At first glance opAssignRight is a really **brilliant** idea šŸ‘.
>> Why do you think that variants would be required ? i += s would work with the single op overload. Maybe it would more be something like
>> 
>> T opExtractRight(T){}, with T saying what type is involved in the operation
>> 
>> int i = sĀ  rewritten asĀ  int i = s.opExtractRight!int();
>> i += sĀ Ā Ā Ā  rewritten asĀ  i += s.opExtractRight!int();
>
> Oh I like this.
> This way it doesn't fight the other operator overloads and can be used (with them) only if they fail as-is.

It looks very much like "opCast" actually and a better named  is "opImplicitConv"
because right now the error message for Mike's little example says "cannot impliclty convert...".
June 18, 2019
On 18/06/2019 4:18 AM, user1234 wrote:
> It looks very much like "opCast" actually and a better namedĀ  is "opImplicitConv"
> because right now the error message for Mike's little example says "cannot impliclty convert...".

I thought about opCast as well, and it does look like it. But its not opCast.

With regards to implicit casting, I don't think it is it.
Implicit casting would be used in many more situations (e.g. return statements and function arguments).
There is quite some push back against those use cases.
June 17, 2019
On Monday, 17 June 2019 at 16:27:59 UTC, rikki cattermole wrote:
> On 18/06/2019 4:18 AM, user1234 wrote:
>> It looks very much like "opCast" actually and a better namedĀ  is "opImplicitConv"
>> because right now the error message for Mike's little example says "cannot impliclty convert...".
>
> I thought about opCast as well, and it does look like it. But its not opCast.
>
> With regards to implicit casting, I don't think it is it.
> Implicit casting would be used in many more situations (e.g. return statements and function arguments).
> There is quite some push back against those use cases.

Semantics to call this possibly new operator must be well defined -> DIP