www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - DIP66 - Multiple alias this

reply "IgorStepanov" <wazar mail.ru> writes:
I've created DIP for my pull request.
DIP: http://wiki.dlang.org/DIP66
PR: https://github.com/D-Programming-Language/dmd/pull/3998

Please, comment it.
Oct 10 2014
next sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 10/10/14 1:09 PM, IgorStepanov wrote:
 I've created DIP for my pull request.
 DIP: http://wiki.dlang.org/DIP66
 PR: https://github.com/D-Programming-Language/dmd/pull/3998

 Please, comment it.
Hm... not sure you need a DIP. From page 231 of TDPL: "A class could introduce any number of alias this declarations, thus subtyping any number of types." -Steve
Oct 10 2014
next sibling parent "IgorStepanov" <wazar mail.ru> writes:
On Friday, 10 October 2014 at 17:31:23 UTC, Steven Schveighoffer 
wrote:
 On 10/10/14 1:09 PM, IgorStepanov wrote:
 I've created DIP for my pull request.
 DIP: http://wiki.dlang.org/DIP66
 PR: https://github.com/D-Programming-Language/dmd/pull/3998

 Please, comment it.
Hm... not sure you need a DIP. From page 231 of TDPL: "A class could introduce any number of alias this declarations, thus subtyping any number of types." -Steve
TDPL tells that multiple alias this should be allowed, but tell nothing about conflict resolving. General idea of this DIP is sistematize rules for alias this. Please comment this part. Maybe I've forgot some cases, maybe introduce dangerous semantic rule.
Oct 10 2014
prev sibling next sibling parent "Brad Anderson" <eco gnuk.net> writes:
On Friday, 10 October 2014 at 17:31:23 UTC, Steven Schveighoffer 
wrote:
 On 10/10/14 1:09 PM, IgorStepanov wrote:
 I've created DIP for my pull request.
 DIP: http://wiki.dlang.org/DIP66
 PR: https://github.com/D-Programming-Language/dmd/pull/3998

 Please, comment it.
Hm... not sure you need a DIP. From page 231 of TDPL: "A class could introduce any number of alias this declarations, thus subtyping any number of types." -Steve
Igor was asked to write a DIP for it by Walter and Andrei. Here's the context: https://github.com/D-Programming-Language/dmd/pull/3998#issuecomment-58286631
Oct 10 2014
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 10/10/14, 10:31 AM, Steven Schveighoffer wrote:
 On 10/10/14 1:09 PM, IgorStepanov wrote:
 I've created DIP for my pull request.
 DIP: http://wiki.dlang.org/DIP66
 PR: https://github.com/D-Programming-Language/dmd/pull/3998

 Please, comment it.
Hm... not sure you need a DIP. From page 231 of TDPL: "A class could introduce any number of alias this declarations, thus subtyping any number of types."
TDPL is not reference. The DIP should cover various corner cases. -- Andrei
Oct 10 2014
parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 10/10/14 2:17 PM, Andrei Alexandrescu wrote:
 On 10/10/14, 10:31 AM, Steven Schveighoffer wrote:
 On 10/10/14 1:09 PM, IgorStepanov wrote:
 I've created DIP for my pull request.
 DIP: http://wiki.dlang.org/DIP66
 PR: https://github.com/D-Programming-Language/dmd/pull/3998

 Please, comment it.
Hm... not sure you need a DIP. From page 231 of TDPL: "A class could introduce any number of alias this declarations, thus subtyping any number of types."
TDPL is not reference. The DIP should cover various corner cases. -- Andrei
OK, thanks everyone. I thought DIPs were specifically for proposals that had not been already approved. -Steve
Oct 10 2014
prev sibling next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 10/10/14, 10:09 AM, IgorStepanov wrote:
 I've created DIP for my pull request.
 DIP: http://wiki.dlang.org/DIP66
 PR: https://github.com/D-Programming-Language/dmd/pull/3998

 Please, comment it.
Thanks, will do. Everybody interested please chime in! -- Andrei
Oct 10 2014
prev sibling next sibling parent reply "Brian Schott" <briancschott gmail.com> writes:
On Friday, 10 October 2014 at 17:09:08 UTC, IgorStepanov wrote:
 I've created DIP for my pull request.
 DIP: http://wiki.dlang.org/DIP66
 PR: https://github.com/D-Programming-Language/dmd/pull/3998

 Please, comment it.
There is an error in the wiki formatting in the second code block. (`{| class="wikitable"` should not be there) I don't see any problems with the actual content of the DIP.
Oct 10 2014
parent "IgorStepanov" <wazar mail.ru> writes:
On Friday, 10 October 2014 at 20:29:43 UTC, Brian Schott wrote:
 On Friday, 10 October 2014 at 17:09:08 UTC, IgorStepanov wrote:
 I've created DIP for my pull request.
 DIP: http://wiki.dlang.org/DIP66
 PR: https://github.com/D-Programming-Language/dmd/pull/3998

 Please, comment it.
There is an error in the wiki formatting in the second code block. (`{| class="wikitable"` should not be there) I don't see any problems with the actual content of the DIP.
Fixed. This is starnge implicit copy-paste of my text editor =/
Oct 10 2014
prev sibling next sibling parent reply "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> writes:
On Friday, 10 October 2014 at 17:09:08 UTC, IgorStepanov wrote:
 I've created DIP for my pull request.
 DIP: http://wiki.dlang.org/DIP66
 PR: https://github.com/D-Programming-Language/dmd/pull/3998

 Please, comment it.
I understand that as a first step it was suggested to implement the strictest behaviour regarding conflicts, namely to disallow them entirely. However, I think more permissive strategies are useful, like in this example: https://github.com/D-Programming-Language/dmd/pull/3998#issuecomment-58570742 Conflict resolution can work like overload resolution, with different levels of matching and partial ordering.
Oct 10 2014
parent "IgorStepanov" <wazar mail.ru> writes:
On Friday, 10 October 2014 at 20:44:11 UTC, Marc Schütz wrote:
 On Friday, 10 October 2014 at 17:09:08 UTC, IgorStepanov wrote:
 I've created DIP for my pull request.
 DIP: http://wiki.dlang.org/DIP66
 PR: https://github.com/D-Programming-Language/dmd/pull/3998

 Please, comment it.
I understand that as a first step it was suggested to implement the strictest behaviour regarding conflicts, namely to disallow them entirely. However, I think more permissive strategies are useful, like in this example: https://github.com/D-Programming-Language/dmd/pull/3998#issuecomment-58570742 Conflict resolution can work like overload resolution, with different levels of matching and partial ordering.
There isn't hard to change resolving strategy. This will need to change one function definition. Thus we able to implement strictest now and after some time of new feature using, relax the behaviour. This will not require significant efforts.
Oct 10 2014
prev sibling next sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 10/10/14 1:09 PM, IgorStepanov wrote:
 I've created DIP for my pull request.
 DIP: http://wiki.dlang.org/DIP66
 PR: https://github.com/D-Programming-Language/dmd/pull/3998

 Please, comment it.
This part: void test() { C c; int i = c; //Error: c.a.i vs c.b.i } static assert(is(C : int)); //Ok, because C is subtype of int anyway. I think might be wrong. There is a lot of code out there that says, e.g.: void foo(T)(T t) if(is(T : U)) { U u = t; ... } Which will now create an error in the wrong place. IMO, the 'is' test should also fail. -Steve
Oct 10 2014
next sibling parent reply "IgorStepanov" <wazar mail.ru> writes:
On Friday, 10 October 2014 at 20:47:45 UTC, Steven Schveighoffer 
wrote:
 On 10/10/14 1:09 PM, IgorStepanov wrote:
 I've created DIP for my pull request.
 DIP: http://wiki.dlang.org/DIP66
 PR: https://github.com/D-Programming-Language/dmd/pull/3998

 Please, comment it.
This part: void test() { C c; int i = c; //Error: c.a.i vs c.b.i } static assert(is(C : int)); //Ok, because C is subtype of int anyway. I think might be wrong. There is a lot of code out there that says, e.g.: void foo(T)(T t) if(is(T : U)) { U u = t; ... } Which will now create an error in the wrong place. IMO, the 'is' test should also fail. -Steve
I thought exactly about this using case. See: You have a struct like this in first place: struct A { int i; alias i this; } struct C { A a; string s; alias a this; alias s this; } And you have a template function in second place: void foo(T)(T t) if(is(T : int)) { ... } void foo(T)(T t) if(is(T : string)) { ... } And you have the code it third place: C c; foo(c); //Error: what do you mean: foo!(T : string) or foo!(T : int) Now, someone (A developer) changed the A definition: struct A { int i; alias i this; } struct B { int i; alias i this; } struct C { A a; B b; string s; alias a this; alias b this; alias s this; } And now, you code mystically start to works. Attention: Infusing in one place conflict resolves conflict in another place. It is danger, I think.
Oct 10 2014
parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 10/10/14 5:15 PM, IgorStepanov wrote:
 On Friday, 10 October 2014 at 20:47:45 UTC, Steven Schveighoffer wrote:
 On 10/10/14 1:09 PM, IgorStepanov wrote:
 I've created DIP for my pull request.
 DIP: http://wiki.dlang.org/DIP66
 PR: https://github.com/D-Programming-Language/dmd/pull/3998

 Please, comment it.
This part: void test() { C c; int i = c; //Error: c.a.i vs c.b.i } static assert(is(C : int)); //Ok, because C is subtype of int anyway. I think might be wrong. There is a lot of code out there that says, e.g.: void foo(T)(T t) if(is(T : U)) { U u = t; ... } Which will now create an error in the wrong place. IMO, the 'is' test should also fail. -Steve
I thought exactly about this using case. See: You have a struct like this in first place: struct A { int i; alias i this; } struct C { A a; string s; alias a this; alias s this; } And you have a template function in second place: void foo(T)(T t) if(is(T : int)) { ... } void foo(T)(T t) if(is(T : string)) { ... } And you have the code it third place: C c; foo(c); //Error: what do you mean: foo!(T : string) or foo!(T : int)
I agree with all this.
 Now, someone (A developer) changed the A definition:

      struct A
      {
          int i;
          alias i this;
      }

      struct B
      {
          int i;
          alias i this;
      }

      struct C
      {
          A a;
          B b;
          string s;
          alias a this;
          alias b this;
          alias s this;
      }

 And now, you code mystically start to works.
Why? It's just as confused as before, no? The way the DIP reads, the call to foo(c) compiles, but the instantiation fails. This can cause subtle issues when you want to select an instantiation based on what it casts to. An example: foo(T)(T t) if(is(T : int)) { someFuncThatTakesInt(t); } foo(T)(T t) if(!is(T : int) && is(T.shadow : int)) { someFuncThatTakesInt(t.shadow); } struct A { int i; alias i this; } struct B { int i; alias i this; } struct C { A a; B shadow; alias a this; alias shadow this; } C c; foo(c); // should compile, but I think your DIP makes it fail due to ambiguity -Steve
Oct 10 2014
parent reply "IgorStepanov" <wazar mail.ru> writes:
On Friday, 10 October 2014 at 21:26:49 UTC, Steven Schveighoffer 
wrote:
 On 10/10/14 5:15 PM, IgorStepanov wrote:
 On Friday, 10 October 2014 at 20:47:45 UTC, Steven 
 Schveighoffer wrote:
 On 10/10/14 1:09 PM, IgorStepanov wrote:
 I've created DIP for my pull request.
 DIP: http://wiki.dlang.org/DIP66
 PR: https://github.com/D-Programming-Language/dmd/pull/3998

 Please, comment it.
This part: void test() { C c; int i = c; //Error: c.a.i vs c.b.i } static assert(is(C : int)); //Ok, because C is subtype of int anyway. I think might be wrong. There is a lot of code out there that says, e.g.: void foo(T)(T t) if(is(T : U)) { U u = t; ... } Which will now create an error in the wrong place. IMO, the 'is' test should also fail. -Steve
I thought exactly about this using case. See: You have a struct like this in first place: struct A { int i; alias i this; } struct C { A a; string s; alias a this; alias s this; } And you have a template function in second place: void foo(T)(T t) if(is(T : int)) { ... } void foo(T)(T t) if(is(T : string)) { ... } And you have the code it third place: C c; foo(c); //Error: what do you mean: foo!(T : string) or foo!(T : int)
I agree with all this.
 Now, someone (A developer) changed the A definition:

     struct A
     {
         int i;
         alias i this;
     }

     struct B
     {
         int i;
         alias i this;
     }

     struct C
     {
         A a;
         B b;
         string s;
         alias a this;
         alias b this;
         alias s this;
     }

 And now, you code mystically start to works.
Why? It's just as confused as before, no? The way the DIP reads, the call to foo(c) compiles, but the instantiation fails. This can cause subtle issues when you want to select an instantiation based on what it casts to. An example: foo(T)(T t) if(is(T : int)) { someFuncThatTakesInt(t); } foo(T)(T t) if(!is(T : int) && is(T.shadow : int)) { someFuncThatTakesInt(t.shadow); } struct A { int i; alias i this; } struct B { int i; alias i this; } struct C { A a; B shadow; alias a this; alias shadow this; } C c; foo(c); // should compile, but I think your DIP makes it fail due to ambiguity -Steve
You can write foo(c.shadow); This isn't hard. Ok, I understood you, let's listen to what others say
Oct 10 2014
parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 10/10/14 6:10 PM, IgorStepanov wrote:
 On Friday, 10 October 2014 at 21:26:49 UTC, Steven Schveighoffer wrote:
 An example:

 foo(T)(T t) if(is(T : int))
 {
    someFuncThatTakesInt(t);
 }

 foo(T)(T t) if(!is(T : int) && is(T.shadow : int))
 {
    someFuncThatTakesInt(t.shadow);
 }

 struct A
 {
    int i;
    alias i this;
 }

 struct B
 {
    int i;
    alias i this;
 }

 struct C
 {
    A a;
    B shadow;
    alias a this;
    alias shadow this;
 }

 C c;
 foo(c); // should compile, but I think your DIP makes it fail due to
 ambiguity
You can write foo(c.shadow); This isn't hard. Ok, I understood you, let's listen to what others say
Right, you can get around it. But the issue here is, that I feel like is(T: U) means (from dlang.org): is ( Type : TypeSpecialization ) The condition is satisfied if Type is semantically correct and it is the same as or can be implicitly converted to TypeSpecialization. This means is(C : int) should indicate that C can implicitly convert to int. But in your DIP, it does not. I think this is incorrect. -Steve
Oct 12 2014
next sibling parent reply "IgorStepanov" <wazar mail.ru> writes:
On Sunday, 12 October 2014 at 23:02:13 UTC, Steven Schveighoffer 
wrote:
 On 10/10/14 6:10 PM, IgorStepanov wrote:
 On Friday, 10 October 2014 at 21:26:49 UTC, Steven 
 Schveighoffer wrote:
 An example:

 foo(T)(T t) if(is(T : int))
 {
   someFuncThatTakesInt(t);
 }

 foo(T)(T t) if(!is(T : int) && is(T.shadow : int))
 {
   someFuncThatTakesInt(t.shadow);
 }

 struct A
 {
   int i;
   alias i this;
 }

 struct B
 {
   int i;
   alias i this;
 }

 struct C
 {
   A a;
   B shadow;
   alias a this;
   alias shadow this;
 }

 C c;
 foo(c); // should compile, but I think your DIP makes it fail 
 due to
 ambiguity
You can write foo(c.shadow); This isn't hard. Ok, I understood you, let's listen to what others say
Right, you can get around it. But the issue here is, that I feel like is(T: U) means (from dlang.org): is ( Type : TypeSpecialization ) The condition is satisfied if Type is semantically correct and it is the same as or can be implicitly converted to TypeSpecialization. This means is(C : int) should indicate that C can implicitly convert to int. But in your DIP, it does not. I think this is incorrect. -Steve
Hmm. I've written case (my previous post), when returning false from is(T: S), where T has many pathes to S is dangerous. However your words also contain the truth. I don't know what we need to do. Maybe we should raise error during "is" semantic? Please, read my example and say your opinion.
Oct 12 2014
parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 10/12/14 7:16 PM, IgorStepanov wrote:
 On Sunday, 12 October 2014 at 23:02:13 UTC, Steven Schveighoffer wrote:
 On 10/10/14 6:10 PM, IgorStepanov wrote:
 You can write foo(c.shadow); This isn't hard.
 Ok, I understood you, let's listen to what others say
Right, you can get around it. But the issue here is, that I feel like is(T: U) means (from dlang.org): is ( Type : TypeSpecialization ) The condition is satisfied if Type is semantically correct and it is the same as or can be implicitly converted to TypeSpecialization. This means is(C : int) should indicate that C can implicitly convert to int. But in your DIP, it does not. I think this is incorrect.
 Hmm. I've written case (my previous post), when returning false from
 is(T: S), where T has many pathes to S is dangerous.
OK, I didn't understand your case before, but I just got it. I understand what you mean, but this isn't anything new -- one can cause weird problems by creating diamond-pattern interfaces also. I do not actually think it is dangerous, because one would not leave an error call in their code. So for a future change to a library to "mystically" make a function start working is not a danger, because said code wasn't sitting there broken in the first place. I will note, that for diamond problem interfaces, the compiler seems to take a different track than your DIP: interface A {} interface B : A {} interface C : A {} class X : B, C {} static assert(is(X : A)); void main() { A a = new C; // works, not sure if it's B.A or C.A } I know this is a different problem -- we aren't pointing at two different concrete implementations. -Steve
Oct 12 2014
parent "IgorStepanov" <wazar mail.ru> writes:
On Monday, 13 October 2014 at 00:54:13 UTC, Steven Schveighoffer 
wrote:
 On 10/12/14 7:16 PM, IgorStepanov wrote:
 On Sunday, 12 October 2014 at 23:02:13 UTC, Steven 
 Schveighoffer wrote:
 On 10/10/14 6:10 PM, IgorStepanov wrote:
 You can write foo(c.shadow); This isn't hard.
 Ok, I understood you, let's listen to what others say
Right, you can get around it. But the issue here is, that I feel like is(T: U) means (from dlang.org): is ( Type : TypeSpecialization ) The condition is satisfied if Type is semantically correct and it is the same as or can be implicitly converted to TypeSpecialization. This means is(C : int) should indicate that C can implicitly convert to int. But in your DIP, it does not. I think this is incorrect.
 Hmm. I've written case (my previous post), when returning 
 false from
 is(T: S), where T has many pathes to S is dangerous.
OK, I didn't understand your case before, but I just got it. I understand what you mean, but this isn't anything new -- one can cause weird problems by creating diamond-pattern interfaces also. I do not actually think it is dangerous, because one would not leave an error call in their code. So for a future change to a library to "mystically" make a function start working is not a danger, because said code wasn't sitting there broken in the first place. I will note, that for diamond problem interfaces, the compiler seems to take a different track than your DIP: interface A {} interface B : A {} interface C : A {} class X : B, C {} static assert(is(X : A)); void main() { A a = new C; // works, not sure if it's B.A or C.A } I know this is a different problem -- we aren't pointing at two different concrete implementations. -Steve
This is fundamentally different situation: interfaces haven't a state, thus don't care what interface will be getted: B.C or C.C. Moreover, we can think that we have only one base C (like virtual inherited class in C++). Alias this case requires a completely different approach.
Oct 13 2014
prev sibling parent "IgorStepanov" <wazar mail.ru> writes:
Advantage of ky way is a more strictness then your way: if 
function with if(is(T: S)) will be called, error will be raised 
at the first trying of convert T to S. And we don't give the 
opportunity of possible error to spread away from the place of 
origin.
Oct 12 2014
prev sibling parent "IgorStepanov" <wazar mail.ru> writes:
 Which will now create an error in the wrong place. IMO, the 
 'is' test should also fail.

 -Steve
In this case, you will see the real error and will able to fix if. For example call foo(c.a); Otherwice, you possible error will be fixed without taking into account your opinions.
Oct 10 2014
prev sibling next sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 10/10/2014 10:09 AM, IgorStepanov wrote:
 I've created DIP for my pull request.
 DIP: http://wiki.dlang.org/DIP66
 PR: https://github.com/D-Programming-Language/dmd/pull/3998

 Please, comment it.
Thanks, Igor!
Oct 10 2014
prev sibling next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 10/10/2014 10:09 AM, IgorStepanov wrote:
 Please, comment it.
 static assert(is(C : int)); //Ok, because C is subtype of int anyway.
Comment should say that C is implicitly convertible to int struct Test1 { int a; int b; alias a this; alias b this; //Error: alias b this conflicts with alias a this; } DIP says this is "obviously incorrect", but what rule is being applied? I suspect the rule here is if typeof(a)==typeof(b), then it is rejected. What if typeof(a) is implicitly convertible to typeof(b), and vice-versa? Is alias this resolved before base class search, after base class search, or is it an error if both searches are successful? If 'a' and 'b' both contain overloads for function foo, then it should behave like imports do (which is a bit complex). Essentially, the rules for multiple alias this should be the same as for multiple imports and multiple mixin templates. These rules work, and the consistency will be expected.
Oct 10 2014
next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 10/10/2014 11:25 PM, Walter Bright wrote:
 Essentially, the rules for multiple alias this should be the same as for
 multiple imports and multiple mixin templates. These rules work, and the
 consistency will be expected.
Agreed. Do you suggest to overload alias this against imports and mixin templates?
Oct 10 2014
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 10/10/2014 3:06 PM, Timon Gehr wrote:
 On 10/10/2014 11:25 PM, Walter Bright wrote:
 Essentially, the rules for multiple alias this should be the same as for
 multiple imports and multiple mixin templates. These rules work, and the
 consistency will be expected.
Agreed. Do you suggest to overload alias this against imports and mixin templates?
I hadn't thought of that (thanks for bringing it up). My first thought is no. Alias this gets searched after those do, because it comes into play only when the symbol isn't resolved in the scope.
Oct 10 2014
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 10/11/2014 12:29 AM, Walter Bright wrote:
 On 10/10/2014 3:06 PM, Timon Gehr wrote:
 On 10/10/2014 11:25 PM, Walter Bright wrote:
 Essentially, the rules for multiple alias this should be the same as for
 multiple imports and multiple mixin templates. These rules work, and the
 consistency will be expected.
Agreed. Do you suggest to overload alias this against imports and mixin templates?
I hadn't thought of that (thanks for bringing it up). My first thought is no. Alias this gets searched after those do, because it comes into play only when the symbol isn't resolved in the scope.
This allows for symbol hijacking (this is also the current behaviour): // --- module m; import std.stdio; // void foo(int x){ writeln("hi from m"); } // uncomment to hijack // --- module main; import std.stdio; struct T{ import m; alias s this; S s; } struct S{ void foo(int x){ writeln("hi from S"); } } void main(){ T t; t.foo(1); }
Oct 10 2014
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 10/10/2014 3:46 PM, Timon Gehr wrote:
 On 10/11/2014 12:29 AM, Walter Bright wrote:
 On 10/10/2014 3:06 PM, Timon Gehr wrote:
 On 10/10/2014 11:25 PM, Walter Bright wrote:
 Essentially, the rules for multiple alias this should be the same as for
 multiple imports and multiple mixin templates. These rules work, and the
 consistency will be expected.
Agreed. Do you suggest to overload alias this against imports and mixin templates?
I hadn't thought of that (thanks for bringing it up). My first thought is no. Alias this gets searched after those do, because it comes into play only when the symbol isn't resolved in the scope.
This allows for symbol hijacking (this is also the current behaviour): // --- module m; import std.stdio; // void foo(int x){ writeln("hi from m"); } // uncomment to hijack // --- module main; import std.stdio; struct T{ import m; alias s this; S s; } struct S{ void foo(int x){ writeln("hi from S"); } } void main(){ T t; t.foo(1); }
Hmm. Good point. The alias this should be done before imports.
Oct 10 2014
parent reply "IgorStepanov" <wazar mail.ru> writes:
On Friday, 10 October 2014 at 22:51:34 UTC, Walter Bright wrote:
 On 10/10/2014 3:46 PM, Timon Gehr wrote:
 On 10/11/2014 12:29 AM, Walter Bright wrote:
 On 10/10/2014 3:06 PM, Timon Gehr wrote:
 On 10/10/2014 11:25 PM, Walter Bright wrote:
 Essentially, the rules for multiple alias this should be 
 the same as for
 multiple imports and multiple mixin templates. These rules 
 work, and the
 consistency will be expected.
Agreed. Do you suggest to overload alias this against imports and mixin templates?
I hadn't thought of that (thanks for bringing it up). My first thought is no. Alias this gets searched after those do, because it comes into play only when the symbol isn't resolved in the scope.
This allows for symbol hijacking (this is also the current behaviour): // --- module m; import std.stdio; // void foo(int x){ writeln("hi from m"); } // uncomment to hijack // --- module main; import std.stdio; struct T{ import m; alias s this; S s; } struct S{ void foo(int x){ writeln("hi from S"); } } void main(){ T t; t.foo(1); }
Hmm. Good point. The alias this should be done before imports.
Symmetrically. You may use symbol from import, uncomment it in aliased type and hijack it.
Oct 10 2014
parent "IgorStepanov" <wazar mail.ru> writes:
BTW.

Overloaded functions in PR resolves un-properly (raises error 
even if can be resolved correct function)
However it's easy to fix and I'll do it tomorrow.
Oct 10 2014
prev sibling parent reply "IgorStepanov" <wazar mail.ru> writes:
On Friday, 10 October 2014 at 21:25:17 UTC, Walter Bright wrote:
 On 10/10/2014 10:09 AM, IgorStepanov wrote:
 Please, comment it.
 static assert(is(C : int)); //Ok, because C is subtype of int
anyway. Comment should say that C is implicitly convertible to int
Not really. int i = C(); //conflict: c.a.i vs c.b.i (thus, C is not implicitly convertible to int)
     struct Test1
     {
         int a;
         int b;
         alias a this;
         alias b this; //Error: alias b this conflicts with 
 alias a this;
     }

 DIP says this is "obviously incorrect", but what rule is being 
 applied? I suspect the rule here is if typeof(a)==typeof(b), 
 then it is rejected.

 What if typeof(a) is implicitly convertible to typeof(b), and 
 vice-versa?
In current state, if "typeof(a) is implicitly convertible to typeof(b), and vice-versa", compiler will accept this alias this declaration. However error may be raised at alias this resolving stage.
 Is alias this resolved before base class search, after base 
 class search, or is it an error if both searches are successful?
In existing alias this implementation alias this resolved after base class search. This DIP inherits it, thus now I suggest to check base classes before alias this. Is it acceptable? Should I add this into DIP?
 If 'a' and 'b' both contain overloads for function foo, then it 
 should behave like imports do (which is a bit complex).
Hmm. Now it works as I wrote it DIP pseudo-code: struct A { void foo(string); void foo(int); } struct B { void foo(double); } struct C { A a; B b; alias a this; alias b this; } C.foo("test"); //found only one acceptable foo: C.a.foo(string) C.foo(5); //1. Check a: found C.a.foo(int); //2. Check b: found C.b.foo(double); //3. Raise error: C.a.foo(int) vs C.b.foo(double) conflict C.foo(5.0); //found only one acceptable foo: C.b.foo(double) Is it Ok?
 Essentially, the rules for multiple alias this should be the 
 same as for multiple imports and multiple mixin templates. 
 These rules work, and the consistency will be expected.
Where can I read about multiple mixin templates?
Oct 10 2014
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 10/11/2014 12:07 AM, IgorStepanov wrote:
 On Friday, 10 October 2014 at 21:25:17 UTC, Walter Bright wrote:
 If 'a' and 'b' both contain overloads for function foo, then it should
 behave like imports do (which is a bit complex).
Hmm. Now it works as I wrote it DIP pseudo-code:
The pseudo-code doesn't actually specify that the arguments the identifier is being called with are considered at all.
 struct A
 {
      void foo(string);
      void foo(int);
 }

 struct B
 {
      void foo(double);
 }

 struct C
 {
      A a;
      B b;
      alias a this;
      alias b this;
 }

 C.foo("test"); //found only one acceptable foo: C.a.foo(string)
 C.foo(5);      //1. Check a: found C.a.foo(int);
                 //2. Check b: found C.b.foo(double);
                 //3. Raise error: C.a.foo(int) vs C.b.foo(double) conflict
 C.foo(5.0);    //found only one acceptable foo: C.b.foo(double)

 Is it Ok?
 ...
That is the right behaviour. What happens in this case: struct A{ void foo(int); void foo(double); } struct B void foo(string); } ... // (struct C and calls as yours) Is it correct that the DIP makes imports at aggregate scope shadow alias this lookups?
Oct 10 2014
parent "IgorStepanov" <wazar mail.ru> writes:
On Friday, 10 October 2014 at 22:18:36 UTC, Timon Gehr wrote:
 On 10/11/2014 12:07 AM, IgorStepanov wrote:
 On Friday, 10 October 2014 at 21:25:17 UTC, Walter Bright 
 wrote:
 If 'a' and 'b' both contain overloads for function foo, then 
 it should
 behave like imports do (which is a bit complex).
Hmm. Now it works as I wrote it DIP pseudo-code:
The pseudo-code doesn't actually specify that the arguments the identifier is being called with are considered at all.
 struct A
 {
     void foo(string);
     void foo(int);
 }

 struct B
 {
     void foo(double);
 }

 struct C
 {
     A a;
     B b;
     alias a this;
     alias b this;
 }

 C.foo("test"); //found only one acceptable foo: C.a.foo(string)
 C.foo(5);      //1. Check a: found C.a.foo(int);
                //2. Check b: found C.b.foo(double);
                //3. Raise error: C.a.foo(int) vs 
 C.b.foo(double) conflict
 C.foo(5.0);    //found only one acceptable foo: C.b.foo(double)

 Is it Ok?
 ...
That is the right behaviour. What happens in this case: struct A{ void foo(int); void foo(double); } struct B void foo(string); } ... // (struct C and calls as yours)
C.foo("test"); //Ok, C.b.foo(string); C.foo(5); //Ok, C.a.foo(int); C.foo(5.0); //Ok, C.a.foo(double); Compiler simply tries to forward c.foo(ARG) -> c.a.foo(ARG) and c.b.foo(ARG). If only one is correct, compiler will accept it. If both is correct, compiler will raise an error.
Oct 10 2014
prev sibling next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 10/10/2014 07:09 PM, IgorStepanov wrote:
 I've created DIP for my pull request.
 DIP: http://wiki.dlang.org/DIP66
 PR: https://github.com/D-Programming-Language/dmd/pull/3998

 Please, comment it.
- "C c; int i = c; //Error: c.a.i vs c.b.i static assert(is(C : int)); //Ok, because C is subtype of int anyway." So now we can have 'subtypes' whose instances cannot be stored in variables of the 'base type'? Such behaviour is inconsistent with both the reference implementation and the documentation (and the two happen to be mutually inconsistent on how 'is(:)' should behave as well. :o) ) - "The following pseudo-code illustrates this: [...] Finally, if resultSet contains only one candidate, the compiler will accept it." This process might very well never terminate but it could terminate in more cases if it did something better than the naive brute-force search. I.e. either report cycles or don't keep exploring around cycles, but just looping indefinitely on cycles like the following is IMO not a good course of action: struct S{ alias get this; T get(){ return T.init; } } struct T{ alias get this; S get(){ return S.init; } int x; alias x this; } void main(){ S s; int x=s; } Furthermore, the following code compiles now, but doesn't under the approach described in the DIP. Is this an actual regression your pull introduces or is there a bug in the pseudocode?: class A{ alias x this; int x; } class B: A{ alias y this; int y; } void main(){ int x = new B(); } The same issue also needs to be considered if A and B are structs instead and B has an additional alias this to an A (the solution might also be part of a fix for the cycle issue). - "If resultSet contains more then one candidates, the compiler raises an error." Why? The language already has a way to deal with cross-scope overload resolution. (Also, what makes candidates different?)
Oct 10 2014
parent reply "IgorStepanov" <wazar mail.ru> writes:
On Friday, 10 October 2014 at 22:05:18 UTC, Timon Gehr wrote:
 On 10/10/2014 07:09 PM, IgorStepanov wrote:
 I've created DIP for my pull request.
 DIP: http://wiki.dlang.org/DIP66
 PR: https://github.com/D-Programming-Language/dmd/pull/3998

 Please, comment it.
- "C c; int i = c; //Error: c.a.i vs c.b.i static assert(is(C : int)); //Ok, because C is subtype of int anyway." So now we can have 'subtypes' whose instances cannot be stored in variables of the 'base type'?
C++ allowed subtypes, which can not be casted to the base type (inheritance of two identical, non-virtual base classes). Ok, I've wrote my position, understood your and wait the decision of the arbitrator:)
 Such behaviour is inconsistent with both the reference 
 implementation and the documentation (and the two happen to be 
 mutually inconsistent on how 'is(:)' should behave as well. :o) 
 )


 - "The following pseudo-code illustrates this: [...] Finally, 
 if resultSet contains only one candidate, the compiler will 
 accept it."

 This process might very well never terminate but it could 
 terminate in more cases if it did something better than the 
 naive brute-force search. I.e. either report cycles or don't 
 keep exploring around cycles, but just looping indefinitely on 
 cycles like the following is IMO not a good course of action:

 struct S{
     alias get this;
     T get(){ return T.init; }
 }
 struct T{
     alias get this;
     S get(){ return S.init; }
     int x;
     alias x this;
 }

 void main(){
     S s;
     int x=s;
 }
This case described in DIP below. Recursion tree will be like: s.get s.get.get ->return, because T is already visited s.x -> win
 Furthermore, the following code compiles now, but doesn't under 
 the approach described in the DIP. Is this an actual regression 
 your pull introduces or is there a bug in the pseudocode?:

 class A{
     alias x this;
     int x;
 }

 class B: A{
     alias y this;
     int y;
 }

 void main(){
     int x = new B();
 }

 The same issue also needs to be considered if A and B are 
 structs instead and B has an additional alias this to an A (the 
 solution might also be part of a fix for the cycle issue).

 - "If resultSet contains more then one candidates, the compiler 
 raises an error."
struct A { short s; alias s this; } struct B { int i; alias i this; } struct C { A a; B b; alias a this; alias b this; } long l = C(); //What do you suggest?
Oct 10 2014
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 10/10/2014 3:20 PM, IgorStepanov wrote:
 The same issue also needs to be considered if A and B are structs instead and
 B has an additional alias this to an A (the solution might also be part of a
 fix for the cycle issue).

 - "If resultSet contains more then one candidates, the compiler raises an
error."
struct A { short s; alias s this; } struct B { int i; alias i this; } struct C { A a; B b; alias a this; alias b this; } long l = C(); //What do you suggest?
The rule would be if: long l = C.a(); long l = C.b(); both compile, then: long l = C(); must be an error, even if one of C.a() or C.b() might be a "better" match. This is how things work for template mixins and imports.
Oct 10 2014
parent reply "IgorStepanov" <wazar mail.ru> writes:
On Friday, 10 October 2014 at 22:50:25 UTC, Walter Bright wrote:
 On 10/10/2014 3:20 PM, IgorStepanov wrote:
 The same issue also needs to be considered if A and B are 
 structs instead and
 B has an additional alias this to an A (the solution might 
 also be part of a
 fix for the cycle issue).

 - "If resultSet contains more then one candidates, the 
 compiler raises an error."
struct A { short s; alias s this; } struct B { int i; alias i this; } struct C { A a; B b; alias a this; alias b this; } long l = C(); //What do you suggest?
The rule would be if: long l = C.a(); long l = C.b(); both compile, then: long l = C(); must be an error, even if one of C.a() or C.b() might be a "better" match. This is how things work for template mixins and imports.
So it is.
Oct 10 2014
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 10/10/2014 4:23 PM, IgorStepanov wrote:
 On Friday, 10 October 2014 at 22:50:25 UTC, Walter Bright wrote:
 must be an error, even if one of C.a() or C.b() might be a "better" match.
 This is how things work for template mixins and imports.
So it is.
Good! The same rule applies for overloading.
Oct 10 2014
parent reply "IgorStepanov" <wazar mail.ru> writes:
On Saturday, 11 October 2014 at 00:00:48 UTC, Walter Bright wrote:
 On 10/10/2014 4:23 PM, IgorStepanov wrote:
 On Friday, 10 October 2014 at 22:50:25 UTC, Walter Bright 
 wrote:
 must be an error, even if one of C.a() or C.b() might be a 
 "better" match.
 This is how things work for template mixins and imports.
So it is.
Good! The same rule applies for overloading.
I've implemented overloading: https://github.com/D-Programming-Language/dmd/pull/3998/files#diff-17b22eae29e74ce6ec29037438b5031cR2136 Please, tell me, what changes should I make to the DIP as a result of yesterday's discussions. And please, tell your opinion about "is" issue: class A { int i; alias i this; } class B { int i; alias i this; } class C { A a; B b; alias a this; alias b this; } void foo(T)(T arg) if(is(T : int)) { ... } foo(C()); //Should it pass or not?
Oct 11 2014
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 10/11/2014 7:23 AM, IgorStepanov wrote:
 On Saturday, 11 October 2014 at 00:00:48 UTC, Walter Bright wrote:
 On 10/10/2014 4:23 PM, IgorStepanov wrote:
 On Friday, 10 October 2014 at 22:50:25 UTC, Walter Bright wrote:
 must be an error, even if one of C.a() or C.b() might be a "better" match.
 This is how things work for template mixins and imports.
So it is.
Good! The same rule applies for overloading.
I've implemented overloading: https://github.com/D-Programming-Language/dmd/pull/3998/files#diff-17b22eae29e74ce6ec29037438b5031cR2136 Please, tell me, what changes should I make to the DIP as a result of yesterday's discussions.
At the very least, it should say it resolves ambiguities the same way that imports and template mixins do.
 And please, tell your opinion about "is" issue:

 class A
 {
     int i;
     alias i this;
 }

 class B
 {
     int i;
     alias i this;
 }

 class C
 {
     A a;
     B b;
     alias a this;
     alias b this;
 }

 void foo(T)(T arg) if(is(T : int))
 {
     ...
 }

 foo(C()); //Should it pass or not?
There's a rule with imports that if the same symbol is reachable via multiple paths through the imports, that it is not an ambiguity error. Here, the same type is reachable through multiple alias this paths, so by analogy it shouldn't be an error.
Oct 11 2014
parent reply "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> writes:
On Sunday, 12 October 2014 at 04:31:22 UTC, Walter Bright wrote:
 On 10/11/2014 7:23 AM, IgorStepanov wrote:
 class A
 {
    int i;
    alias i this;
 }

 class B
 {
    int i;
    alias i this;
 }

 class C
 {
    A a;
    B b;
    alias a this;
    alias b this;
 }

 void foo(T)(T arg) if(is(T : int))
 {
    ...
 }

 foo(C()); //Should it pass or not?
There's a rule with imports that if the same symbol is reachable via multiple paths through the imports, that it is not an ambiguity error. Here, the same type is reachable through multiple alias this paths, so by analogy it shouldn't be an error.
It's the same type, but different symbols; actual accesses would be ambiguous. `is(T : int)` shouldn't evaluate to true if `int a = T.init;` would fail.
Oct 12 2014
parent reply "IgorStepanov" <wazar mail.ru> writes:
On Sunday, 12 October 2014 at 08:36:05 UTC, Marc Schütz wrote:
 On Sunday, 12 October 2014 at 04:31:22 UTC, Walter Bright wrote:
 On 10/11/2014 7:23 AM, IgorStepanov wrote:
 class A
 {
   int i;
   alias i this;
 }

 class B
 {
   int i;
   alias i this;
 }

 class C
 {
   A a;
   B b;
   alias a this;
   alias b this;
 }

 void foo(T)(T arg) if(is(T : int))
 {
   ...
 }

 foo(C()); //Should it pass or not?
There's a rule with imports that if the same symbol is reachable via multiple paths through the imports, that it is not an ambiguity error. Here, the same type is reachable through multiple alias this paths, so by analogy it shouldn't be an error.
It's the same type, but different symbols; actual accesses would be ambiguous. `is(T : int)` shouldn't evaluate to true if `int a = T.init;` would fail.
I found an example of a situation that is bothering me. Let we have a persistence framework, which provides a storing D object in some persistence storage: DB, file et c. In introduces paired functions store/load and special type PersistenceObject. If stored type is subtype of PersistenceObject it converts to PersistenceObject and PersistenceObject.load(stream) called for loading object (and PersistenceObject.store(stream) for storing). Otherwice if object can't be converted to PersistenceObject it should be serialized via "serialize" function (or deserialized via "deserialize"). struct PersistenceFramework { void store(T)(T arg) if (is(T : PersistenceObject)) { PersistenceObject po = arg; arg.store(stream); } void store(T)(T arg) if (!is(T : PersistenceObject)) { PersistenceObject po = arg; store(serialize(arg)); } void load(T)(ref T arg) if (is(T : PersistenceObject)) { PersistenceObject po = arg; arg.load(stream); } void load(T)(ref T arg) if (!is(T : PersistenceObject)) { PersistenceObject po = arg; load(serialize(arg)); } Stream stream; } /**************************************************************** And we have the next types which we want to store and load *****************************************************************/ struct Role { ... } struct User { Role role; PersistenceObject po; //... alias role this; alias po this; } /*****************************************************************/ User u; persistenceFramework.load(u) //... persistenceFramework.store(u); /******************************************************************/ Role is not subtype of PersistenceObject thus all works ok. We can store User via User.po and load it again; Some time later, Role designer decided that Role should be subtype of PersistenceObject and changed Role definition: struct Role { ... PersistenceObject po; alias po this; } Now, User can not be converted to PersistenceObject because there are two path to convert: User.po and User.role.po; Storing code after this change will be copiled successfully (if we follow your "is" rule), however object will be tried to load via "void load(T)(ref T arg) if (!is(T : PersistenceObject))". Because object was saved via "void store(T)(T arg) if (is(T : PersistenceObject))" at the previous program run, user will not be loaded succesfully. Moreover, you will get an strange unexpected program behaviour and will be hard to find real error cause. /*****************************************************************/ And finally, if you want to check, if you Type _really_ can be converted to AnotherType, you can use the next check: void foo(Type)(Type arg) if (is(typeof({AnotherType x = Type.init;}))) { }
Oct 12 2014
parent reply "Daniel N" <ufo orbiting.us> writes:
 On 10/11/2014 7:23 AM, IgorStepanov wrote:
 class A
 {
  int i;
  alias i this;
 }

 class B
 {
  int i;
  alias i this;
 }

 class C
 {
  A a;
  B b;
  alias a this;
  alias b this;
 }
My preferred solution would be to reject the 2nd alias declaration outright. I don't see any value in intentionally creating the above pattern, _if_ it occurs then it's most likely due to an unintentional side-effect of a re-factoring, thus it should error out as close as possible to the real error.
Oct 13 2014
parent reply "IgorStepanov" <wazar mail.ru> writes:
On Monday, 13 October 2014 at 15:21:32 UTC, Daniel N wrote:
 On 10/11/2014 7:23 AM, IgorStepanov wrote:
 class A
 {
 int i;
 alias i this;
 }

 class B
 {
 int i;
 alias i this;
 }

 class C
 {
 A a;
 B b;
 alias a this;
 alias b this;
 }
My preferred solution would be to reject the 2nd alias declaration outright. I don't see any value in intentionally creating the above pattern, _if_ it occurs then it's most likely due to an unintentional side-effect of a re-factoring, thus it should error out as close as possible to the real error.
This code tell that C is subtype of A and C is subtype of B. User can use this fact in his code: void foo(B); C c = new C; foo(c); //Ok. Of course, we shouldn't allow user to cast c to int: int i = c; //wrong However, user can explicitly cast c to his subtype, which is convertable to int: int i = cast(B)c; //Ok Summarizing, I disagree with suggestion disallow this code at type semantic stage.
Oct 14 2014
parent reply "Dicebot" <public dicebot.lv> writes:
On Tuesday, 14 October 2014 at 12:33:50 UTC, IgorStepanov wrote:
 This code tell that C is subtype of A and C is subtype of B.
 User can use this fact in his code:
 void foo(B);

 C c = new C;
 foo(c); //Ok.
 Of course, we shouldn't allow user to cast c to int:
 int i = c; //wrong
 However, user can explicitly cast c to his subtype, which is 
 convertable to int:
 int i = cast(B)c; //Ok
 Summarizing, I disagree with suggestion disallow this code at 
 type semantic stage.
I agree. It will also make possible to break already working disambugation of `foo(c)` kind but adding new `alias this` to one of subtypes independently. That sounds annoying.
Oct 14 2014
parent reply "Daniel N" <ufo orbiting.us> writes:
On Wednesday, 15 October 2014 at 02:46:05 UTC, Dicebot wrote:
 On Tuesday, 14 October 2014 at 12:33:50 UTC, IgorStepanov wrote:
 This code tell that C is subtype of A and C is subtype of B.
 User can use this fact in his code:
 void foo(B);

 C c = new C;
 foo(c); //Ok.
 Of course, we shouldn't allow user to cast c to int:
 int i = c; //wrong
 However, user can explicitly cast c to his subtype, which is 
 convertable to int:
 int i = cast(B)c; //Ok
 Summarizing, I disagree with suggestion disallow this code at 
 type semantic stage.
I agree. It will also make possible to break already working disambugation of `foo(c)` kind but adding new `alias this` to one of subtypes independently. That sounds annoying.
I guess the best part of D is, you have the means to fix anything you disagree with yourself... I can add a static assert to my class and be happy. I have another idea, we could define that the shortest conversion chain wins, analogous to type promotions, that makes it possible to contain the issue inside C. class C { A a; B b; int disambiguate_int() { return a; } alias a this; alias b this; alias disambiguate_int this; static assert(__traits(compiles, {int _ = C.init;}), "Ambiguous alias this"); } i.e. this assert should pass.
Oct 14 2014
parent reply "IgorStepanov" <wazar mail.ru> writes:
On Wednesday, 15 October 2014 at 03:49:41 UTC, Daniel N wrote:
 On Wednesday, 15 October 2014 at 02:46:05 UTC, Dicebot wrote:
 On Tuesday, 14 October 2014 at 12:33:50 UTC, IgorStepanov 
 wrote:
 This code tell that C is subtype of A and C is subtype of B.
 User can use this fact in his code:
 void foo(B);

 C c = new C;
 foo(c); //Ok.
 Of course, we shouldn't allow user to cast c to int:
 int i = c; //wrong
 However, user can explicitly cast c to his subtype, which is 
 convertable to int:
 int i = cast(B)c; //Ok
 Summarizing, I disagree with suggestion disallow this code at 
 type semantic stage.
I agree. It will also make possible to break already working disambugation of `foo(c)` kind but adding new `alias this` to one of subtypes independently. That sounds annoying.
I guess the best part of D is, you have the means to fix anything you disagree with yourself... I can add a static assert to my class and be happy. I have another idea, we could define that the shortest conversion chain wins, analogous to type promotions, that makes it possible to contain the issue inside C. class C { A a; B b; int disambiguate_int() { return a; } alias a this; alias b this; alias disambiguate_int this; static assert(__traits(compiles, {int _ = C.init;}), "Ambiguous alias this"); } i.e. this assert should pass.
In first edition I've implemented rule, when if type defines alias this directly, this alias hides all indirect aliases with the same type. However Andrey said that we should implement the strictest rules as possible and maybe relax them later. Thus I implemented current rules, but saved the old implemetation of search. After some time we will able to return to first rule. It's not hard.
Oct 15 2014
next sibling parent reply "IgorStepanov" <wazar mail.ru> writes:
Bump.
Oct 19 2014
next sibling parent reply "Dicebot" <public dicebot.lv> writes:
On Sunday, 19 October 2014 at 21:00:29 UTC, IgorStepanov wrote:
 Bump.
For me current description and PR look solid and safe enough to try.
Oct 21 2014
parent reply "IgorStepanov" <wazar mail.ru> writes:
On Tuesday, 21 October 2014 at 08:17:19 UTC, Dicebot wrote:
 On Sunday, 19 October 2014 at 21:00:29 UTC, IgorStepanov wrote:
 Bump.
For me current description and PR look solid and safe enough to try.
We are waiting for an Andrey's Word. Walter, as I understand haven't unresolved objections.
Oct 21 2014
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 10/21/14 1:24 PM, IgorStepanov wrote:
 On Tuesday, 21 October 2014 at 08:17:19 UTC, Dicebot wrote:
 On Sunday, 19 October 2014 at 21:00:29 UTC, IgorStepanov wrote:
 Bump.
For me current description and PR look solid and safe enough to try.
We are waiting for an Andrey's Word. Walter, as I understand haven't unresolved objections.
There are issues with the proposal. I must get to them today. -- Andrei
Oct 27 2014
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 10/19/14 2:00 PM, IgorStepanov wrote:
 Bump.
I've made a few grammar and fluency edits to the DIP, and collected a few thoughts while doing that. Will get back on this before too long. -- Andrei
Oct 23 2014
parent reply "IgorStepanov" <wazar mail.ru> writes:
On Friday, 24 October 2014 at 06:04:24 UTC, Andrei Alexandrescu 
wrote:
 On 10/19/14 2:00 PM, IgorStepanov wrote:
 Bump.
I've made a few grammar and fluency edits to the DIP, and collected a few thoughts while doing that. Will get back on this before too long. -- Andrei
I've seen it. Thanks! Waiting for a comments. Should I add chapter about method overloading with alias this: it should work (and works) as cross-module overloading. It should imply This implies from the DIP but hasn't written explicitly. OT: Should `et\s?c\.?` be written as "etc" in English? I thought that it should be written as "et c.", because "et cetera". Or is it an anachronism?
Oct 24 2014
next sibling parent reply "Meta" <jared771 gmail.com> writes:
On Friday, 24 October 2014 at 13:05:54 UTC, IgorStepanov wrote:
 On Friday, 24 October 2014 at 06:04:24 UTC, Andrei Alexandrescu 
 wrote:
 On 10/19/14 2:00 PM, IgorStepanov wrote:
 Bump.
I've made a few grammar and fluency edits to the DIP, and collected a few thoughts while doing that. Will get back on this before too long. -- Andrei
I've seen it. Thanks! Waiting for a comments. Should I add chapter about method overloading with alias this: it should work (and works) as cross-module overloading. It should imply This implies from the DIP but hasn't written explicitly. OT: Should `et\s?c\.?` be written as "etc" in English? I thought that it should be written as "et c.", because "et cetera". Or is it an anachronism?
The convention is to write "etc.", with the period indicating that the rest of the word has been omitted. If it appears in the middle of a sentence, I don't capitalize the subsequent word as it doesn't really make sense, but I'm not sure what the actual convention is in that respect.
Oct 24 2014
next sibling parent "John Colvin" <john.loughran.colvin gmail.com> writes:
On Friday, 24 October 2014 at 13:17:28 UTC, Meta wrote:
 On Friday, 24 October 2014 at 13:05:54 UTC, IgorStepanov wrote:
 On Friday, 24 October 2014 at 06:04:24 UTC, Andrei 
 Alexandrescu wrote:
 On 10/19/14 2:00 PM, IgorStepanov wrote:
 Bump.
I've made a few grammar and fluency edits to the DIP, and collected a few thoughts while doing that. Will get back on this before too long. -- Andrei
I've seen it. Thanks! Waiting for a comments. Should I add chapter about method overloading with alias this: it should work (and works) as cross-module overloading. It should imply This implies from the DIP but hasn't written explicitly. OT: Should `et\s?c\.?` be written as "etc" in English? I thought that it should be written as "et c.", because "et cetera". Or is it an anachronism?
The convention is to write "etc.", with the period indicating that the rest of the word has been omitted. If it appears in the middle of a sentence, I don't capitalize the subsequent word as it doesn't really make sense, but I'm not sure what the actual convention is in that respect.
A full stop (a.k.a. period in some countries) for abbreviation does not imply that the following word must be capitalised. Sentences must start with a capital.
Oct 24 2014
prev sibling parent "IgorStepanov" <wazar mail.ru> writes:
On Friday, 24 October 2014 at 13:17:28 UTC, Meta wrote:
 On Friday, 24 October 2014 at 13:05:54 UTC, IgorStepanov wrote:
 On Friday, 24 October 2014 at 06:04:24 UTC, Andrei 
 Alexandrescu wrote:
 On 10/19/14 2:00 PM, IgorStepanov wrote:
 Bump.
I've made a few grammar and fluency edits to the DIP, and collected a few thoughts while doing that. Will get back on this before too long. -- Andrei
I've seen it. Thanks! Waiting for a comments. Should I add chapter about method overloading with alias this: it should work (and works) as cross-module overloading. It should imply This implies from the DIP but hasn't written explicitly. OT: Should `et\s?c\.?` be written as "etc" in English? I thought that it should be written as "et c.", because "et cetera". Or is it an anachronism?
The convention is to write "etc.", with the period indicating that the rest of the word has been omitted. If it appears in the middle of a sentence, I don't capitalize the subsequent word as it doesn't really make sense, but I'm not sure what the actual convention is in that respect.
Thanks for the explanation:)
Oct 24 2014
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 10/24/14 6:05 AM, IgorStepanov wrote:
 On Friday, 24 October 2014 at 06:04:24 UTC, Andrei Alexandrescu wrote:
 On 10/19/14 2:00 PM, IgorStepanov wrote:
 Bump.
I've made a few grammar and fluency edits to the DIP, and collected a few thoughts while doing that. Will get back on this before too long. -- Andrei
I've seen it. Thanks! Waiting for a comments.
Coming soon. I've been under quite a bit of pressure as of late.
 Should I add chapter about method overloading with alias this: it should
 work (and works) as cross-module overloading. It should imply
 This implies from the DIP but hasn't written explicitly.
Interesting. I think it should work like overloading of calls in base and derived classes.
 OT: Should `et\s?c\.?` be written as "etc" in English?
 I thought that it should be written as "et c.", because "et cetera". Or
 is it an anachronism?
You can't go wrong with M-W: http://www.merriam-webster.com/dictionary/etc Andrei
Oct 27 2014
parent "IgorStepanov" <wazar mail.ru> writes:
On Tuesday, 28 October 2014 at 02:07:23 UTC, Andrei Alexandrescu 
wrote:
 On 10/24/14 6:05 AM, IgorStepanov wrote:
 On Friday, 24 October 2014 at 06:04:24 UTC, Andrei 
 Alexandrescu wrote:
 On 10/19/14 2:00 PM, IgorStepanov wrote:
 Bump.
I've made a few grammar and fluency edits to the DIP, and collected a few thoughts while doing that. Will get back on this before too long. -- Andrei
I've seen it. Thanks! Waiting for a comments.
Coming soon. I've been under quite a bit of pressure as of late.
 Should I add chapter about method overloading with alias this: 
 it should
 work (and works) as cross-module overloading. It should imply
 This implies from the DIP but hasn't written explicitly.
Interesting. I think it should work like overloading of calls in base and derived classes.
Not really. Rules which define overloading class methods doesn't describe multiple inheritance case. In single inheritance case alias this rule is similar with inheritance rule: derived overload set hides base base overload set: struct A { void foo(string) { writeln("string"); } void foo(int) { writeln("int"); } } struct B { void foo(double) { writeln("double"); } A a; alias a this; } B b; b.foo("string"); //error b.foo(42); //called B.foo(double), not B.a.foo(int); The second test is not similar to inherintance rules, but this case is not relevant with multiple alias this and it is already done. When I said "cross-module overloading", I told about case when C inherits (via alias this) A and B, both A and B have "foo" methods with different paramethers and compiler should resolve foo call: struct A { void foo(string) { writeln("string"); } void foo(int) { writeln("int"); } } struct B { void foo(double) { writeln("double"); } } struct C { A a; B b; alias a this; alias b this; } C c; c.foo("str"); // OK, c.a.foo(string) c.foo(4.2); //OK, c.b.foo(double); c.foo(42); //Error: c.a.foo(int) or c.b.foo(double)? BTW, similar case with multiple inheritance via interfaces works absolutely incorrect: interface CA { final void foo(string) { writeln("string"); } final void foo(int) { writeln("int"); } } interface CB { final void foo(double) { writeln("double"); } } class CC : CA, CB { } auto cc = new CC(); cc.foo("xxx"); //OK, called CA.foo(string) cc.foo(42); //called CA.foo(int) without any warnings cc.foo(4.2); //Error: unable to call CA.foo with double argument. In other words, compiler choses the first base interface, uses its overload set and ignores other interfaces.
 OT: Should `et\s?c\.?` be written as "etc" in English?
 I thought that it should be written as "et c.", because "et 
 cetera". Or
 is it an anachronism?
You can't go wrong with M-W: http://www.merriam-webster.com/dictionary/etc
Thanks.
Oct 28 2014
prev sibling parent reply "Daniel N" <ufo orbiting.us> writes:
On Wednesday, 15 October 2014 at 09:50:17 UTC, IgorStepanov wrote:
 In first edition I've implemented rule, when if type defines 
 alias this directly, this alias hides all indirect aliases with 
 the same type. However Andrey said that we should implement the 
 strictest rules as possible and maybe relax them later.
 Thus I implemented current rules, but saved the old 
 implemetation of search. After some time we will able to return 
 to first rule. It's not hard.
I see, in order to prevent any accidental shadowing, maybe one can consider "override alias this", if we decide to make a relaxed version in the future?
Oct 19 2014
parent "IgorStepanov" <wazar mail.ru> writes:
On Monday, 20 October 2014 at 00:23:46 UTC, Daniel N wrote:
 On Wednesday, 15 October 2014 at 09:50:17 UTC, IgorStepanov 
 wrote:
 In first edition I've implemented rule, when if type defines 
 alias this directly, this alias hides all indirect aliases 
 with the same type. However Andrey said that we should 
 implement the strictest rules as possible and maybe relax them 
 later.
 Thus I implemented current rules, but saved the old 
 implemetation of search. After some time we will able to 
 return to first rule. It's not hard.
I see, in order to prevent any accidental shadowing, maybe one can consider "override alias this", if we decide to make a relaxed version in the future?
Make sense. I think we should postpone but not forgotten this feature. When main part will be merged, we will able to start discussion about override alias this. What about the other features?
Oct 19 2014
prev sibling next sibling parent reply Joseph Rushton Wakeling via Digitalmars-d <digitalmars-d puremagic.com> writes:
On 10/10/14 19:09, IgorStepanov via Digitalmars-d wrote:
 I've created DIP for my pull request.
 DIP: http://wiki.dlang.org/DIP66
 PR: https://github.com/D-Programming-Language/dmd/pull/3998

 Please, comment it.
This may be beyond the scope of the DIP, but is there any intention (or any need?) to set rules for how alias this should behave in the case of different protection levels for the base type and the alias? I ask because there is a known issue related to this: https://issues.dlang.org/show_bug.cgi?id=10996 ... but also because any rules set for this, might in principle affect the desirable priority rules for multiple alias this too.
Oct 10 2014
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 10/10/2014 3:27 PM, Joseph Rushton Wakeling via Digitalmars-d wrote:
 On 10/10/14 19:09, IgorStepanov via Digitalmars-d wrote:
 I've created DIP for my pull request.
 DIP: http://wiki.dlang.org/DIP66
 PR: https://github.com/D-Programming-Language/dmd/pull/3998

 Please, comment it.
This may be beyond the scope of the DIP, but is there any intention (or any need?) to set rules for how alias this should behave in the case of different protection levels for the base type and the alias?
I like the C++ rule that says that access control is not considered for name lookup. I know it makes for some annoying results, but the simplicity of the rule makes it much more understandable.
 I ask because there is a known issue related to this:
 https://issues.dlang.org/show_bug.cgi?id=10996

 ... but also because any rules set for this, might in principle affect the
 desirable priority rules for multiple alias this too.
Oct 10 2014
next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2014-10-11 00:52, Walter Bright wrote:

 I like the C++ rule that says that access control is not considered for
 name lookup. I know it makes for some annoying results, but the
 simplicity of the rule makes it much more understandable.
I'm not so sure about that. Perhaps it makes it more understandable for a language designer. But not for a user. You try to call a function but you get a conflict with a private symbol. The user will get frustrated thinking: "stupid compiler, of course I want to call the public function". -- /Jacob Carlborg
Oct 11 2014
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 10/11/2014 3:42 AM, Jacob Carlborg wrote:
 On 2014-10-11 00:52, Walter Bright wrote:

 I like the C++ rule that says that access control is not considered for
 name lookup. I know it makes for some annoying results, but the
 simplicity of the rule makes it much more understandable.
I'm not so sure about that. Perhaps it makes it more understandable for a language designer. But not for a user. You try to call a function but you get a conflict with a private symbol. The user will get frustrated thinking: "stupid compiler, of course I want to call the public function".
The theory is that simpler rules are better than complex rules, even if the simpler rules aren't always ideal.
Oct 11 2014
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 10/12/2014 06:28 AM, Walter Bright wrote:
 On 10/11/2014 3:42 AM, Jacob Carlborg wrote:
 On 2014-10-11 00:52, Walter Bright wrote:

 I like the C++ rule that says that access control is not considered for
 name lookup. I know it makes for some annoying results, but the
 simplicity of the rule makes it much more understandable.
I'm not so sure about that. Perhaps it makes it more understandable for a language designer. But not for a user. You try to call a function but you get a conflict with a private symbol. The user will get frustrated thinking: "stupid compiler, of course I want to call the public function".
The theory is that simpler rules are better than complex rules, even if the simpler rules aren't always ideal.
Public symbols conflicting with private symbols are not just not ideal, they are a major PITA. The procedure for resolving ambiguities using alias introduces new private symbols itself!
Oct 12 2014
prev sibling parent Joseph Rushton Wakeling via Digitalmars-d <digitalmars-d puremagic.com> writes:
On 11/10/14 00:52, Walter Bright via Digitalmars-d wrote:
 I like the C++ rule that says that access control is not considered for name
 lookup. I know it makes for some annoying results, but the simplicity of the
 rule makes it much more understandable.
That's fine. I just wanted to be sure that there wasn't a risk of multiple alias this breaking in unpleasant ways, if/when https://issues.dlang.org/show_bug.cgi?id=10996 is fixed.
Oct 12 2014
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 10/10/14 10:09 AM, IgorStepanov wrote:
 I've created DIP for my pull request.
 DIP: http://wiki.dlang.org/DIP66
 PR: https://github.com/D-Programming-Language/dmd/pull/3998

 Please, comment it.
Here's my destruction: * "symbol can be a field or a get-property (method annotated with property and taking zero parameters)." -> actually: (a) the property annotation is not necessary (b) there may be one ore more parameters so long as they're all defaulted So the text should be "obj.symbol must be a valid expression". * "At the AliasThis declaration semantic stage, the compiler can perform the initial checks and reject the obviously incorrect AliasThis declarations." -> it might be simpler (for the sake of simplifying generic code) to just delay all error checking to the first use. * I don't think the pseudocode helps a lot. Better let's have a clear and precise specification (I've edited the lookup order into an ordered list). * Regarding the lookup, opDispatch shouldn't come before alias this, or should come before base class lookup. Essentially alias this is subtyping so it should enjoy similar privileges to base classes. A different way to look at it is opDispatch is a "last resort" lookup mechanism, just one step above the UFCS lowering. * The DIP should specify the working of alias this as rewrites/lowerings, not pseudocode. Basically for each kth declaration "alias symbolk this;" the compiler rewrites "obj.xyz" as "obj.symbolk.xyz" and then does the usual lookup on that expression. That means the whole algorithms is applied again etc. If more than one rewrite typechecks, that's an ambiguity error. * IMPORTANT: The DIP must discuss rvalue vs. lvalue cases. The rewrite approach simplifies that discussion because it's clear what happens by simply reasoning about the rewritten expression. Lvalue vs. rvalue matters a lot practically. Consider: struct A { private int x; alias x this; } struct B { private int _x; int x() { return x; } alias x this; } Then x can be passed by reference, modified directly etc. for A but not for B. =========== Congratulations on taking this to a DIP. It clarifies things really nice and it's an example to follow for future language changes. Andrei
Oct 28 2014
next sibling parent reply "IgorStepanov" <wazar mail.ru> writes:
On Tuesday, 28 October 2014 at 19:45:09 UTC, Andrei Alexandrescu 
wrote:
 On 10/10/14 10:09 AM, IgorStepanov wrote:
 I've created DIP for my pull request.
 DIP: http://wiki.dlang.org/DIP66
 PR: https://github.com/D-Programming-Language/dmd/pull/3998

 Please, comment it.
Here's my destruction: * "symbol can be a field or a get-property (method annotated with property and taking zero parameters)." -> actually: (a) the property annotation is not necessary (b) there may be one ore more parameters so long as they're all defaulted So the text should be "obj.symbol must be a valid expression". * "At the AliasThis declaration semantic stage, the compiler can perform the initial checks and reject the obviously incorrect AliasThis declarations." -> it might be simpler (for the sake of simplifying generic code) to just delay all error checking to the first use. * I don't think the pseudocode helps a lot. Better let's have a clear and precise specification (I've edited the lookup order into an ordered list). * Regarding the lookup, opDispatch shouldn't come before alias this, or should come before base class lookup. Essentially alias this is subtyping so it should enjoy similar privileges to base classes. A different way to look at it is opDispatch is a "last resort" lookup mechanism, just one step above the UFCS lowering. * The DIP should specify the working of alias this as rewrites/lowerings, not pseudocode. Basically for each kth declaration "alias symbolk this;" the compiler rewrites "obj.xyz" as "obj.symbolk.xyz" and then does the usual lookup on that expression. That means the whole algorithms is applied again etc. If more than one rewrite typechecks, that's an ambiguity error. * IMPORTANT: The DIP must discuss rvalue vs. lvalue cases. The rewrite approach simplifies that discussion because it's clear what happens by simply reasoning about the rewritten expression. Lvalue vs. rvalue matters a lot practically. Consider: struct A { private int x; alias x this; } struct B { private int _x; int x() { return x; } alias x this; } Then x can be passed by reference, modified directly etc. for A but not for B. =========== Congratulations on taking this to a DIP. It clarifies things really nice and it's an example to follow for future language changes. Andrei
Thanks for answer, I hope, I'll able to to carefully consider your comments tomorrow. Now I want to ask about the one thing. What do you think about compatibility with existing alias this implementation? For example you wrote: "Regarding the lookup, opDispatch shouldn't come before alias this, or should come before base class lookup.". This requirement breaks the existing code. We can apply this change in DIP, however if we want to apply this change to compiler, we should be careful. Moreover, I don't see the way to create deprecation path: old implementation->deprecated old implementation & new inmplementation -> prohibited old implementation & new inmplementation. If we will change the semantic order of proprerty resolving, we will not able to warn user about changes. Suddenly his code will be compiled in a different way. And please comment my way to resolving "is" expression via alias-this: http://forum.dlang.org/thread/ubafmwvxwtolhmnxbrsf forum.dlang.org?page=5 Thanks for the DIP review.
Oct 28 2014
parent reply "Meta" <jared771 gmail.com> writes:
On Tuesday, 28 October 2014 at 20:09:07 UTC, IgorStepanov wrote:
 And please comment my way to resolving "is" expression via 
 alias-this:
 http://forum.dlang.org/thread/ubafmwvxwtolhmnxbrsf forum.dlang.org?page=5
Something else related to the discussion about `is` from this thread: http://forum.dlang.org/post/tulvmydnogbgebnxybfk forum.dlang.org. The following code: import std.math; import std.traits; struct S(T) if(isFloatingPoint!T) { T val; alias val this; } void main() { auto s = S!float(); assert(isNaN(s)); s = 10.0; assert(!isNaN(s)); } Current fails to compile with this error: Error: template std.math.isNaN cannot deduce function from argument types !()(S!float), candidates are: std/math.d(4171): std.math.isNaN(X)(X x) if (isFloatingPoint!X) Is this a problem with the current implementation of `alias this`, or should isFloatingPoint be changed so that it also accepts types that alias a floating point type?
Oct 28 2014
next sibling parent "Meta" <jared771 gmail.com> writes:
On Tuesday, 28 October 2014 at 21:55:35 UTC, Meta wrote:
 or should isFloatingPoint be changed so that it also accepts 
 types that alias a floating point type?
My mistake, I mean isNaN and similar functions, such as isNumeric.
Oct 28 2014
prev sibling parent reply "IgorStepanov" <wazar mail.ru> writes:
On Tuesday, 28 October 2014 at 21:55:35 UTC, Meta wrote:
 On Tuesday, 28 October 2014 at 20:09:07 UTC, IgorStepanov wrote:
 And please comment my way to resolving "is" expression via 
 alias-this:
 http://forum.dlang.org/thread/ubafmwvxwtolhmnxbrsf forum.dlang.org?page=5
Something else related to the discussion about `is` from this thread: http://forum.dlang.org/post/tulvmydnogbgebnxybfk forum.dlang.org. The following code: import std.math; import std.traits; struct S(T) if(isFloatingPoint!T) { T val; alias val this; } void main() { auto s = S!float(); assert(isNaN(s)); s = 10.0; assert(!isNaN(s)); } Current fails to compile with this error: Error: template std.math.isNaN cannot deduce function from argument types !()(S!float), candidates are: std/math.d(4171): std.math.isNaN(X)(X x) if (isFloatingPoint!X) Is this a problem with the current implementation of `alias this`, or should isFloatingPoint be changed so that it also accepts types that alias a floating point type?
You may see isFloatingPoint declaration in traits.d: enum bool isFloatingPoint(T) = is(FloatingPointTypeOf!T) && !isAggregateType!T; This template explicitly says that T shouldn't be an aggregate type. Thus std.math.isNaN(X)(X x) if (isFloatingPoint!X) shouldn't accept a struct.
Oct 28 2014
parent reply "Meta" <jared771 gmail.com> writes:
On Tuesday, 28 October 2014 at 22:55:24 UTC, IgorStepanov wrote:
 You may see isFloatingPoint declaration in traits.d:
 enum bool isFloatingPoint(T) = is(FloatingPointTypeOf!T) && 
 !isAggregateType!T;

 This template explicitly says that T shouldn't be an aggregate 
 type. Thus
 std.math.isNaN(X)(X x) if (isFloatingPoint!X)
 shouldn't accept a struct.
Although alias this is supposed to denote subtyping, here is a violation of the Liskov Substitution Principle; although S is a subtype of float, there are some cases where it's invalid to substitute an S for a float. This seems like a problem with alias this to me. As S is aliased to float, typeof(s.val) should be passed to isFloatingPoint if passing S fails.
Oct 28 2014
parent "IgorStepanov" <wazar mail.ru> writes:
On Tuesday, 28 October 2014 at 23:12:21 UTC, Meta wrote:
 On Tuesday, 28 October 2014 at 22:55:24 UTC, IgorStepanov wrote:
 You may see isFloatingPoint declaration in traits.d:
 enum bool isFloatingPoint(T) = is(FloatingPointTypeOf!T) && 
 !isAggregateType!T;

 This template explicitly says that T shouldn't be an aggregate 
 type. Thus
 std.math.isNaN(X)(X x) if (isFloatingPoint!X)
 shouldn't accept a struct.
Although alias this is supposed to denote subtyping, here is a violation of the Liskov Substitution Principle; although S is a subtype of float, there are some cases where it's invalid to substitute an S for a float. This seems like a problem with alias this to me. As S is aliased to float, typeof(s.val) should be passed to isFloatingPoint if passing S fails.
Your issue is not relevant with alias this implementation. isFloatingPoint is a library implemented trait, which uses compile-time reflections to for verifying the truth of the approval "T is floating point type". If you think that isFloatingPoint implemented incorrectly, you may start corresponding discussion. Otherwice, if you think that std.math.isNaN should accept user types which may be converted to floating point type, you may discuss that. If you want simply solve you problem you may define own auto isNaN(T)(S!(T) arg) { return isNaN(cast(T)arg); }
Oct 29 2014
prev sibling parent reply "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= writes:
You should rethink implementing multiple alias this. D is 
increasingly becoming a poorly typed language.

"alias this" is basically static prototype-based programming.

http://en.wikipedia.org/wiki/Prototype-based_programming

Self had multiple inheritance based on prototypes and removed it 
because it was not much used and lead to problems when figuring 
out which methods were called.
Oct 28 2014
parent "Dicebot" <public dicebot.lv> writes:
On Tuesday, 28 October 2014 at 22:58:53 UTC, Ola Fosheim Grøstad 
wrote:
 You should rethink implementing multiple alias this. D is 
 increasingly becoming a poorly typed language.

 "alias this" is basically static prototype-based programming.

 http://en.wikipedia.org/wiki/Prototype-based_programming

 Self had multiple inheritance based on prototypes and removed 
 it because it was not much used and lead to problems when 
 figuring out which methods were called.
No. D is as poorly typed as one wants is to be and multiple alias this is a necessary tool to achieve strong static typing without sacrificing expressiveness.
Oct 31 2014
prev sibling next sibling parent Mike B Johnson <Mikey Ikes.com> writes:
On Friday, 10 October 2014 at 17:09:08 UTC, IgorStepanov wrote:
 I've created DIP for my pull request.
 DIP: http://wiki.dlang.org/DIP66
 PR: https://github.com/D-Programming-Language/dmd/pull/3998

 Please, comment it.
Well, nearly 3 years later and nothing!
Jun 04 2017
prev sibling next sibling parent reply sighoya <sighoya gmail.com> writes:
On Friday, 10 October 2014 at 17:09:08 UTC, IgorStepanov wrote:
 I've created DIP for my pull request.
 DIP: http://wiki.dlang.org/DIP66
 PR: https://github.com/D-Programming-Language/dmd/pull/3998

 Please, comment it.
What's the state?
Mar 20 2019
parent reply Mike Franklin <slavo5150 yahoo.com> writes:
On Wednesday, 20 March 2019 at 21:39:48 UTC, sighoya wrote:
 On Friday, 10 October 2014 at 17:09:08 UTC, IgorStepanov wrote:
 I've created DIP for my pull request.
 DIP: http://wiki.dlang.org/DIP66
 PR: https://github.com/D-Programming-Language/dmd/pull/3998

 Please, comment it.
What's the state?
https://github.com/dlang/dmd/pull/8378 It's waiting on someone willing to work with reviewers to refactor it and integrate it into the codebase to reviewers' satisfaction. Mike
Mar 20 2019
parent reply sighoya <sighoya gmail.com> writes:
On Wednesday, 20 March 2019 at 21:50:55 UTC, Mike Franklin wrote:
 On Wednesday, 20 March 2019 at 21:39:48 UTC, sighoya wrote:
 On Friday, 10 October 2014 at 17:09:08 UTC, IgorStepanov wrote:
 I've created DIP for my pull request.
 DIP: http://wiki.dlang.org/DIP66
 PR: https://github.com/D-Programming-Language/dmd/pull/3998

 Please, comment it.
What's the state?
https://github.com/dlang/dmd/pull/8378 It's waiting on someone willing to work with reviewers to refactor it and integrate it into the codebase to reviewers' satisfaction. Mike
How can I help if I'm not the one creating the PR?
Mar 20 2019
parent reply Mike Franklin <slavo5150 yahoo.com> writes:
On Wednesday, 20 March 2019 at 21:58:46 UTC, sighoya wrote:

 How can I help if I'm not the one creating the PR?
It needs someone willing to adopt the PR and work with reviewers to get it across the finish line. If you've never worked on DMD before, cloning the DMD, druntime, Phobos, etc. and learning how to build the compiler and run the test suite locally is the first step. Mike
Mar 20 2019
next sibling parent reply sighoya <sighoya gmail.com> writes:
On Wednesday, 20 March 2019 at 22:11:00 UTC, Mike Franklin wrote:
 On Wednesday, 20 March 2019 at 21:58:46 UTC, sighoya wrote:

 How can I help if I'm not the one creating the PR?
It needs someone willing to adopt the PR and work with reviewers to get it across the finish line. If you've never worked on DMD before, cloning the DMD, druntime, Phobos, etc. and learning how to build the compiler and run the test suite locally is the first step. Mike
So I can become a reviewer only, but how can I propose changes to be merged into the PR proposer's branch, do I need to clone his branch and to create a pull request in hope he accept my changes?
Mar 21 2019
parent reply Mike Franklin <slavo5150 yahoo.com> writes:
On Thursday, 21 March 2019 at 07:08:41 UTC, sighoya wrote:

 So I can become a reviewer only, but how can I propose changes 
 to be merged into the PR proposer's branch, do I need to clone 
 his branch and to create a pull request in hope he accept my 
 changes?
Create a new branch, merge the original author's work into your branch, then add your edits, and submit a new PR. That's what I'd do anyway. Mike
Mar 21 2019
parent reply sighoya <sighoya gmail.com> writes:
On Thursday, 21 March 2019 at 11:17:52 UTC, Mike Franklin wrote:
 Create a new branch, merge the original author's work into your 
 branch, then add your edits, and submit a new PR.  That's what 
 I'd do anyway.

 Mike
Glad to hear. But does it make sense when there is already one pull request open: https://github.com/dlang/dmd/pull/8378 ?
Mar 21 2019
parent Mike Franklin <slavo5150 yahoo.com> writes:
On Thursday, 21 March 2019 at 11:29:54 UTC, sighoya wrote:
 On Thursday, 21 March 2019 at 11:17:52 UTC, Mike Franklin wrote:
 Create a new branch, merge the original author's work into 
 your branch, then add your edits, and submit a new PR.  That's 
 what I'd do anyway.

 Mike
Glad to hear. But does it make sense when there is already one pull request open: https://github.com/dlang/dmd/pull/8378 ?
IMO, yes. Mike
Mar 21 2019
prev sibling parent sighoya <sighoya gmail.com> writes:
On Wednesday, 20 March 2019 at 22:11:00 UTC, Mike Franklin wrote:
 On Wednesday, 20 March 2019 at 21:58:46 UTC, sighoya wrote:

 How can I help if I'm not the one creating the PR?
It needs someone willing to adopt the PR and work with reviewers to get it across the finish line. If you've never worked on DMD before, cloning the DMD, druntime, Phobos, etc. and learning how to build the compiler and run the test suite locally is the first step. Mike
So I can become a reviewer only, but how can I merge additions requested by reviewers, this can only be done by the PR proposer, right?
Mar 21 2019
prev sibling parent reply IGotD- <nise nise.com> writes:
On Friday, 10 October 2014 at 17:09:08 UTC, IgorStepanov wrote:
 I've created DIP for my pull request.
 DIP: http://wiki.dlang.org/DIP66
 PR: https://github.com/D-Programming-Language/dmd/pull/3998

 Please, comment it.
What happened to this dip? Do we have an implementation or not and what is the holdup for this being added to the compiler? It's been over one year. Multiple alias this would help me a lot and I want (multiple alias) this.
Sep 27 2020
parent reply 12345swordy <alexanderheistermann gmail.com> writes:
On Sunday, 27 September 2020 at 20:43:29 UTC, IGotD- wrote:
 On Friday, 10 October 2014 at 17:09:08 UTC, IgorStepanov wrote:
 I've created DIP for my pull request.
 DIP: http://wiki.dlang.org/DIP66
 PR: https://github.com/D-Programming-Language/dmd/pull/3998

 Please, comment it.
What happened to this dip? Do we have an implementation or not and what is the holdup for this being added to the compiler? It's been over one year. Multiple alias this would help me a lot and I want (multiple alias) this.
It been deprecated as Walter discovered that the current alias this introduce the diamond problem. That and other sorts of bugs that it has. -Alex
Sep 27 2020
next sibling parent reply IGotD- <nise nise.com> writes:
On Sunday, 27 September 2020 at 21:52:15 UTC, 12345swordy wrote:
 It been deprecated as Walter discovered that the current alias 
 this introduce the diamond problem. That and other sorts of 
 bugs that it has.

 -Alex
It doesn't because it isn't inheritance. What you can end up with is symbol collisions but in that case you can just give an error message. You can always go to the Rust forum and first try to convince them that Rust has multiple inheritance and then that Rust is evil because it has that. Good luck.
Sep 27 2020
parent reply 12345swordy <alexanderheistermann gmail.com> writes:
On Sunday, 27 September 2020 at 22:23:27 UTC, IGotD- wrote:
 On Sunday, 27 September 2020 at 21:52:15 UTC, 12345swordy wrote:
 It been deprecated as Walter discovered that the current alias 
 this introduce the diamond problem. That and other sorts of 
 bugs that it has.

 -Alex
It doesn't because it isn't inheritance.
Walter has comment on this on reddit already. It is not happening. I'm sorry to disappoint you. What do you need multi alias this for anyway? Composite programming can already do what alias this can do expect implicit conversion. -Alex
Sep 27 2020
parent reply IGotD- <nise nise.com> writes:
On Sunday, 27 September 2020 at 23:34:31 UTC, 12345swordy wrote:
 What do you need multi alias this for anyway? Composite 
 programming can already do what alias this can do expect 
 implicit conversion.

 -Alex
Yes, exactly that, creating multiple composites. I know that you can do it with mixin templates but kind of ugly. So if I have an implementation, I need a struct with that implementation in it's pure form and also structs where the implementation is inserted. Now you have a disconnected implementation and then a base struct to begin with. So if you want to reuse your code you basically have to make mixin templates of everything. Was it that solution you were referring to?
Sep 27 2020
parent 12345swordy <alexanderheistermann gmail.com> writes:
On Sunday, 27 September 2020 at 23:53:17 UTC, IGotD- wrote:
 On Sunday, 27 September 2020 at 23:34:31 UTC, 12345swordy wrote:
 What do you need multi alias this for anyway? Composite 
 programming can already do what alias this can do expect 
 implicit conversion.

 -Alex
Yes, exactly that, creating multiple composites. I know that you can do it with mixin templates but kind of ugly. So if I have an implementation, I need a struct with that implementation in it's pure form and also structs where the implementation is inserted. Now you have a disconnected implementation and then a base struct to begin with. So if you want to reuse your code you basically have to make mixin templates of everything. Was it that solution you were referring to?
That is the solution that Walter has suggest to us. What issue that you take with this solution? Increase compile times? -Alex
Sep 27 2020
prev sibling next sibling parent Ruby The Roobster <michaeleverestc79 gmail.com> writes:
On Sunday, 27 September 2020 at 21:52:15 UTC, 12345swordy wrote:
 It been deprecated as Walter discovered that the current alias 
 this introduce the diamond problem. That and other sorts of 
 bugs that it has.

 -Alex
Couldn't this be fixed by not having inheritance of alias this?
Sep 27 2020
prev sibling parent reply IGotD- <nise nise.com> writes:
On Sunday, 27 September 2020 at 21:52:15 UTC, 12345swordy wrote:
 It been deprecated as Walter discovered that the current alias 
 this introduce the diamond problem. That and other sorts of 
 bugs that it has.

 -Alex
I must criticize the cop out that many language designers claim about the diamond problem. The diamond problem is mainly an academic problem which doesn't happen much in real life. I have programmed C++ for decades and I have only encountered the diamond problem once in my lifetime and this because I was hacking around, changed the solution shortly after so that it could do without "public virtual". You can come very far with multiple inheritance without the diamond pattern. Are you saying that the detection of the diamond inheritance pattern is hard to implement, I would say that it isn't. If it detects, just emit a compiler error telling the user that such pattern isn't allowed. The diamond problem is like a fantasy monster under the bed of the language designers.
Sep 28 2020
next sibling parent reply 12345swordy <alexanderheistermann gmail.com> writes:
On Monday, 28 September 2020 at 15:01:45 UTC, IGotD- wrote:
 On Sunday, 27 September 2020 at 21:52:15 UTC, 12345swordy wrote:
 [...]
I must criticize the cop out that many language designers claim about the diamond problem. The diamond problem is mainly an academic problem which doesn't happen much in real life. I have programmed C++ for decades and I have only encountered the diamond problem once in my lifetime and this because I was hacking around, changed the solution shortly after so that it could do without "public virtual". You can come very far with multiple inheritance without the diamond pattern. Are you saying that the detection of the diamond inheritance pattern is hard to implement, I would say that it isn't. If it detects, just emit a compiler error telling the user that such pattern isn't allowed. The diamond problem is like a fantasy monster under the bed of the language designers.
Then by all means created a new thread on this and argue your case, as I am not convinced that you think it is easy to implement the diamond inheritance detection. -Alex
Sep 28 2020
parent IGotD- <nise nise.com> writes:
On Monday, 28 September 2020 at 17:16:31 UTC, 12345swordy wrote:
 Then by all means created a new thread on this and argue your 
 case, as I am not convinced that you think it is easy to 
 implement the diamond inheritance detection.

 -Alex
First limit multiple alias this to only be valid for basic types and structs (classes are disqualified for example). Then create a list of all the types that one alias this type has also searching that type for alias this types and up in the alias this hierarchy. If one or more of the same type is found in several alias this type lists, then abort compilation. Maybe there are more efficient ways to do this but you get the idea. Am I missing something?
Sep 28 2020
prev sibling parent reply mw <mingwu gmail.com> writes:
On Monday, 28 September 2020 at 15:01:45 UTC, IGotD- wrote:
 On Sunday, 27 September 2020 at 21:52:15 UTC, 12345swordy wrote:

 I must criticize the cop out that many language designers claim 
 about the diamond problem. The diamond problem is mainly an 
 academic problem which doesn't happen much in real life. I have 
 programmed C++ for decades and I have only encountered the 
 diamond problem once in my lifetime and this because I was 
 hacking around, changed the solution shortly after so that it 
 could do without "public virtual". You can come very far with 
 multiple inheritance without the diamond pattern.

 Are you saying that the detection of the diamond inheritance 
 pattern is hard to implement, I would say that it isn't. If it 
 detects, just emit a compiler error telling the user that such 
 pattern isn't allowed.

 The diamond problem is like a fantasy monster under the bed of 
 the language designers.
I think this deserved to be better known: The diamond problem is a *solved* problem by Eiffel language, which won the 2006 ACM Software System Award: https://en.wikipedia.org/wiki/ACM_Software_System_Award And I showed the concrete example here: https://forum.dlang.org/thread/obqthozmxwzhvrafothw forum.dlang.org
Sep 28 2020
parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Mon, Sep 28, 2020 at 05:59:19PM +0000, mw via Digitalmars-d wrote:
 I think this deserved to be better known:
 
 The diamond problem is a *solved* problem by Eiffel language, which
 won the 2006 ACM Software System Award:
 
 https://en.wikipedia.org/wiki/ACM_Software_System_Award
That award has nothing to do with the diamond problem. There is nothing in the link that even mentions the diamond problem.
 And I showed the concrete example here:
 
 https://forum.dlang.org/thread/obqthozmxwzhvrafothw forum.dlang.org
As somebody already said, that's all well and good for Eiffel. It's not so clear how to integrate this nicely in D. T -- Старый друг лучше новых двух.
Sep 28 2020
next sibling parent reply mw <mingwu gmail.com> writes:
On Monday, 28 September 2020 at 18:13:15 UTC, H. S. Teoh wrote:
 On Mon, Sep 28, 2020 at 05:59:19PM +0000, mw via Digitalmars-d 
 wrote:

 As somebody already said, that's all well and good for Eiffel. 
 It's not so clear how to integrate this nicely in D.
D has `alias` already, which can be used as Eiffel's `rename`, and by introducing the other same keywords (mechanism), we can adopt the Eiffel multiple inheritance. D and Eiffel are close: D picked design-by-contract from Eiffel, but throw away multiple inheritance, ... and instead introduced sub-typing, mixin, which Walter said: https://forum.dlang.org/post/rb4seo$bfm$1 digitalmars.com """ The trouble was, it was inserted without realizing it was multiple inheritance, meaning its behaviors are ad-hoc and don't make a whole lot of sense when examined carefully. """ If we really want to fix it, can do it in D3.
Sep 28 2020
parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Mon, Sep 28, 2020 at 06:28:05PM +0000, mw via Digitalmars-d wrote:
 On Monday, 28 September 2020 at 18:13:15 UTC, H. S. Teoh wrote:
 On Mon, Sep 28, 2020 at 05:59:19PM +0000, mw via Digitalmars-d wrote:
 
 As somebody already said, that's all well and good for Eiffel. It's
 not so clear how to integrate this nicely in D.
D has `alias` already,
[...] `alias this` is one of the things that seemed like a good idea at the time, but is turning out to be something that leads to code smells. If anything, we'd like to get rid of it rather than extend it! T -- People say I'm indecisive, but I'm not sure about that. -- YHL, CONLANG
Sep 28 2020
next sibling parent reply mw <mingwu gmail.com> writes:
On Monday, 28 September 2020 at 18:44:51 UTC, H. S. Teoh wrote:
 On Mon, Sep 28, 2020 at 06:28:05PM +0000, mw via Digitalmars-d 
 wrote:
 On Monday, 28 September 2020 at 18:13:15 UTC, H. S. Teoh wrote:
 On Mon, Sep 28, 2020 at 05:59:19PM +0000, mw via 
 Digitalmars-d wrote:
 
 As somebody already said, that's all well and good for 
 Eiffel. It's not so clear how to integrate this nicely in D.
D has `alias` already,
[...] `alias this` is one of the things that seemed like a good idea at the time, but is turning out to be something that leads to code smells. If anything, we'd like to get rid of it rather than extend it!
On a second thought, I agree we'd better not to extend `alias`. It's all about resolve name clashing: `alias` means synonyms; let's just borrow from Eiffel, instead of re-invent the wheels: the main concepts to solve multiple inheritance are these 5 keywords: https://www.eiffel.org/doc/eiffel/Eiffel_programming_language_reserved_words `rename` `export` `undefine` `redefine` -- D's override `select`
Sep 28 2020
parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Mon, Sep 28, 2020 at 06:56:40PM +0000, mw via Digitalmars-d wrote:
[...]
 It's all about resolve name clashing: `alias` means synonyms; let's
 just borrow from Eiffel, instead of re-invent the wheels: the main
 concepts to solve multiple inheritance are these 5 keywords:
 
 https://www.eiffel.org/doc/eiffel/Eiffel_programming_language_reserved_words
 
 `rename`
 `export`
 `undefine`
 `redefine`   -- D's override
 `select`
I don't know Eiffel; could you enlighten me as to how it solves the following instance of the diamond problem? struct Resource { this(...) { acquireResource(); } ~this() { releaseResource(); } } class A { Resource x; } class B : A { ... } class C : A { ... } class D : B, C { // Should D have one instance of A.x, or two instances // of A.x? (Putting aside the question of naming for the // time being -- let's pretend we have a way of // addressing x somehow in either case.) } I can see some situations for which you want two distinct instances of A.x (there should be two distinct resources acquired by D), and some other situations for which you want them to be the same (the same resource should be shared by B and C). How does Eiffel cater to both cases? Regardless of how Eiffel does it, supporting either case in D is going to be a mess, because it changes the memory layout of B and C, meaning you'd have to decide beforehand which solution is desired, even if D hasn't even been written yet (and the need to implement D hasn't even come up yet). The only way I can think of to support both cases without requiring foretelling the future is to access A's members via a virtual table, which will basically break a lot of the ABI, introduce another layer of indirection (with its performance implications), and require extensive rewriting of D's codegen, etc.. Basically, a HUGE amount of work to implement it and fix the resulting breakage, all for the marginal (I'd even say questionable) benefit of being able to use multiple inheritance. I honestly doubt this will ever happen in D, even if you set aside the question of whether this is even a good idea to begin with. T -- For every argument for something, there is always an equal and opposite argument against it. Debates don't give answers, only wounded or inflated egos.
Sep 28 2020
parent reply mw <mingwu gmail.com> writes:
On Monday, 28 September 2020 at 19:41:07 UTC, H. S. Teoh wrote:
 On Mon, Sep 28, 2020 at 06:56:40PM +0000, mw via Digitalmars-d 
 wrote: [...]
 It's all about resolve name clashing: `alias` means synonyms; 
 let's just borrow from Eiffel, instead of re-invent the 
 wheels: the main concepts to solve multiple inheritance are 
 these 5 keywords:
 
 https://www.eiffel.org/doc/eiffel/Eiffel_programming_language_reserved_words
 
 `rename`
 `export`
 `undefine`
 `redefine`   -- D's override
 `select`
I don't know Eiffel; could you enlighten me as to how it solves the following instance of the diamond problem? struct Resource { this(...) { acquireResource(); } ~this() { releaseResource(); } } class A { Resource x; } class B : A { ... } class C : A { ... } class D : B, C { // Should D have one instance of A.x, or two instances // of A.x? (Putting aside the question of naming for the // time being -- let's pretend we have a way of // addressing x somehow in either case.) } I can see some situations for which you want two distinct instances of A.x (there should be two distinct resources acquired by D), and some other situations for which you want them to be the same (the same resource should be shared by B and C). How does Eiffel cater to both cases?
The Resource A.x in your example is what I have shown in my example PERSON.addr and PERSON.name here: https://forum.dlang.org/thread/obqthozmxwzhvrafothw forum.dlang.org 1) In Eiffel, by default the attribute is shared/joined, meaning in your above code as it its, there is only 1 `x` in D; and that's the PERSON.name in my example (no special treatment, it's just joined in D). 2) If the application do want separate instances of one attribute, PERSON.addr in my example, then use `rename` / `select` to choose the one the programmer wanted semantics in mind. So in this case, your example is: class B : A {...} class C : A {...} // let's suppose the application's semantics want to use C.x, but still keep B.x class D1 : B(rename x as bx) // (rename ...) is my invented Eiffel syntax in D , C(select x) { // (select ...) is my invented Eiffel syntax in D ... } // let's suppose the application's semantics want to use B.x, but still keep C.x class D2 : B(select x) , C(rename x as cx) { ... } // let's suppose the application's semantics want to use B.x, but remove C.x class D3 : B(select x) , C(undefine x) { ... } // let's suppose the application's semantics want to use C.x, but remove B.x class D4 : B(undefine x) , C(select x) { ... } // let's suppose the application's semantics want to remove both B.x and C.x class D5 : B(undefine x) , C(undefine x) { redefine x; // need to redefine x } // let's suppose the application's semantics want to remove keep B.x and C.x class D6 : B(rename x as bx) , C(rename x as cx) { redefine x; // need to redefine x } ... as you can see, all different application semantics can be specified by the programmer. Please check my previous PERSON.addr example more carefully. PERSON.addr UK_RESIDENT(: PERSON).addr US_RESIDENT(: PERSON).addr VISITOR(: UK_RESIDENT, US_RESIDENT).addr https://forum.dlang.org/post/obqthozmxwzhvrafothw forum.dlang.org
Sep 28 2020
parent reply mw <mingwu gmail.com> writes:
On Monday, 28 September 2020 at 20:28:17 UTC, mw wrote:
 On Monday, 28 September 2020 at 19:41:07 UTC, H. S. Teoh wrote:
 I can see some situations for which you want two distinct 
 instances of A.x (there should be two distinct resources 
 acquired by D), and some other situations for which you want 
 them to be the same (the same resource should be shared by B 
 and C).  How does Eiffel cater to both cases?
I didn't handle just 2 cases, but all kinds of cases, whether in the Derived class D.x. you want *any* or even *none* of A.x, B.x, C.x, all kinds of combination, the programmer can specify exactly what s/he wanted using -- undefine -- redefine -- rename -- select I showed 5 examples in Eiffel way, you can do it as an exercise of all the other combinations.
Sep 28 2020
parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Mon, Sep 28, 2020 at 08:45:33PM +0000, mw via Digitalmars-d wrote:
 On Monday, 28 September 2020 at 20:28:17 UTC, mw wrote:
 On Monday, 28 September 2020 at 19:41:07 UTC, H. S. Teoh wrote:
 I can see some situations for which you want two distinct
 instances of A.x (there should be two distinct resources acquired
 by D), and some other situations for which you want them to be the
 same (the same resource should be shared by B and C).  How does
 Eiffel cater to both cases?
I didn't handle just 2 cases, but all kinds of cases, whether in the Derived class D.x. you want *any* or even *none* of A.x, B.x, C.x, all kinds of combination, the programmer can specify exactly what s/he wanted using -- undefine -- redefine -- rename -- select I showed 5 examples in Eiffel way, you can do it as an exercise of all the other combinations.
Good. Now make it work for D. :-P Note that this is easy to do in Eiffel because it has a dynamic memory layout; D does not. Making it work for D will be extremely complex, and probably will not justify the comparatively meager benefits relative to the cost. T -- Today's society is one of specialization: as you grow, you learn more and more about less and less. Eventually, you know everything about nothing.
Sep 28 2020
parent mw <mingwu gmail.com> writes:
On Monday, 28 September 2020 at 21:11:04 UTC, H. S. Teoh wrote:
 Good. Now make it work for D. :-P

 Note that this is easy to do in Eiffel because it has a dynamic 
 memory layout; D does not.  Making it work for D will be
Not sure what you mean by dynamic memory layout. Eiffel is a statically compiled language. All the class's memory layout is know at compile time (as it's fully specified by the programmer in the source code). BTW, many (if not all) Eiffel compilers actually compile Eiffel program to C (as target language). I just uploaded SmartEiffel (open source) 1.1 compiler, and my previous visitor example to: https://github.com/mingwugmail/dlang_tour/tree/master/eiffel You can play with it. And the generated C code of my example is: https://github.com/mingwugmail/dlang_tour/blob/master/eiffel/visitor/app1.c You can study it.
 extremely complex, and probably will not justify the 
 comparatively meager benefits relative to the cost.
Well, we are solving the sub-typing `alias this` & various mixin problems here in Dlang in the very thread.
Sep 28 2020
prev sibling next sibling parent IGotD- <nise nise.com> writes:
On Monday, 28 September 2020 at 18:44:51 UTC, H. S. Teoh wrote:
 [...]

 `alias this` is one of the things that seemed like a good idea 
 at the time, but is turning out to be something that leads to 
 code smells.  If anything, we'd like to get rid of it rather 
 than extend it!


 T
So what is the alternative? I'm not that enthusiastic of mixin templates because it just inserts everything like you would copy and paste text. That way you have to be careful when using several mixin templates that they don't use the exact same variable name for example so it kind of becomes inconvenient. What happens with private: and public:, do they bleed over into the non mixin code? I like alias this because it still offers a way to encapsulation what you want to insert. Multiple inheritance isn't that much of a problem as interfaces solves that but still you want to be able to reuse implementations and not create wrappers for inner structs/classes by hand in every instance you use it.
Sep 28 2020
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.com> writes:
On 9/28/20 2:44 PM, H. S. Teoh wrote:
 On Mon, Sep 28, 2020 at 06:28:05PM +0000, mw via Digitalmars-d wrote:
 On Monday, 28 September 2020 at 18:13:15 UTC, H. S. Teoh wrote:
 On Mon, Sep 28, 2020 at 05:59:19PM +0000, mw via Digitalmars-d wrote:

 As somebody already said, that's all well and good for Eiffel. It's
 not so clear how to integrate this nicely in D.
D has `alias` already,
[...] `alias this` is one of the things that seemed like a good idea at the time, but is turning out to be something that leads to code smells. If anything, we'd like to get rid of it rather than extend it!
I'd love to get a better idea about this, e.g. a few clear examples of bad uses and other few good examples where it's a win. My intuition vaguely revolves around "aliasing to an rvalue is bad and lvalue is good" but I year for clarity.
Sep 28 2020
next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.com> writes:
On 9/28/20 3:55 PM, Andrei Alexandrescu wrote:
 On 9/28/20 2:44 PM, H. S. Teoh wrote:
 On Mon, Sep 28, 2020 at 06:28:05PM +0000, mw via Digitalmars-d wrote:
 On Monday, 28 September 2020 at 18:13:15 UTC, H. S. Teoh wrote:
 On Mon, Sep 28, 2020 at 05:59:19PM +0000, mw via Digitalmars-d wrote:

 As somebody already said, that's all well and good for Eiffel. It's
 not so clear how to integrate this nicely in D.
D has `alias` already,
[...] `alias this` is one of the things that seemed like a good idea at the time, but is turning out to be something that leads to code smells.  If anything, we'd like to get rid of it rather than extend it!
I'd love to get a better idea about this, e.g. a few clear examples of bad uses and other few good examples where it's a win. My intuition vaguely revolves around "aliasing to an rvalue is bad and lvalue is good" but I year for clarity.
s/year/yearn/
Sep 28 2020
prev sibling next sibling parent 12345swordy <alexanderheistermann gmail.com> writes:
On Monday, 28 September 2020 at 19:55:10 UTC, Andrei Alexandrescu 
wrote:
 On 9/28/20 2:44 PM, H. S. Teoh wrote:
 On Mon, Sep 28, 2020 at 06:28:05PM +0000, mw via Digitalmars-d 
 wrote:
 On Monday, 28 September 2020 at 18:13:15 UTC, H. S. Teoh 
 wrote:
 On Mon, Sep 28, 2020 at 05:59:19PM +0000, mw via 
 Digitalmars-d wrote:

 As somebody already said, that's all well and good for 
 Eiffel. It's
 not so clear how to integrate this nicely in D.
D has `alias` already,
[...] `alias this` is one of the things that seemed like a good idea at the time, but is turning out to be something that leads to code smells. If anything, we'd like to get rid of it rather than extend it!
I'd love to get a better idea about this, e.g. a few clear examples of bad uses and other few good examples where it's a win. My intuition vaguely revolves around "aliasing to an rvalue is bad and lvalue is good" but I year for clarity.
An example of bad use is when you "alias this" a class inside a class. A good case is when you "alias this" a struct inside a struct. An ideal case for me is allowing classes to implement opimplicit that strictly returns a copy of a value type, so that we can get rid alias this for classes. -Alex
Sep 28 2020
prev sibling next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 9/28/2020 12:55 PM, Andrei Alexandrescu wrote:
 I'd love to get a better idea about this, e.g. a few clear examples of bad
uses 
 and other few good examples where it's a win. My intuition vaguely revolves 
 around "aliasing to an rvalue is bad and lvalue is good" but I year for
clarity.
There are several bugzilla issues on alias this that aren't fixed because there was no clear way to do it that both made sense and did not break existing code. If a class hierarchy has alias this, when does the compiler go looking down the alias this, and when does it go looking at the base class and interfaces? (Of course the base class can have an alias this, and an alias this can have a base class.) You have essentially *two* multiple inheritance systems in play at the same time, each obeying different rules. Couple that with the current arbitrary random rules about how alias this behaves for classes, and any coherent MI alias this scheme would randomly break existing code.
Sep 28 2020
parent reply 12345swordy <alexanderheistermann gmail.com> writes:
On Tuesday, 29 September 2020 at 03:53:02 UTC, Walter Bright 
wrote:
 On 9/28/2020 12:55 PM, Andrei Alexandrescu wrote:
 [...]
There are several bugzilla issues on alias this that aren't fixed because there was no clear way to do it that both made sense and did not break existing code. If a class hierarchy has alias this, when does the compiler go looking down the alias this, and when does it go looking at the base class and interfaces? (Of course the base class can have an alias this, and an alias this can have a base class.) You have essentially *two* multiple inheritance systems in play at the same time, each obeying different rules. Couple that with the current arbitrary random rules about how alias this behaves for classes, and any coherent MI alias this scheme would randomly break existing code.
You could take Manu Evans advice and allow structs to inherent from other structs traditionally like in c++ and deprecate alias this. That would solve 80 percent of the problem. - Alex
Sep 29 2020
parent reply Paul Backus <snarwin gmail.com> writes:
On Tuesday, 29 September 2020 at 13:17:50 UTC, 12345swordy wrote:
 You could take Manu Evans advice and allow structs to inherent 
 from other structs traditionally like in c++ and deprecate 
 alias this.

 That would solve 80 percent of the problem.

 - Alex
I did a grep for `alias this` in Phobos last time this topic came up. By my count, use of `alias this` was split almost exactly 50/50 between forwarding to a member variable and forwarding to the result of a method.
Sep 29 2020
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 9/29/20 9:13 PM, Paul Backus wrote:
 On Tuesday, 29 September 2020 at 13:17:50 UTC, 12345swordy wrote:
 You could take Manu Evans advice and allow structs to inherent from 
 other structs traditionally like in c++ and deprecate alias this.

 That would solve 80 percent of the problem.

 - Alex
I did a grep for `alias this` in Phobos last time this topic came up. By my count, use of `alias this` was split almost exactly 50/50 between forwarding to a member variable and forwarding to the result of a method.
How frequently did the method return ref vs rvalue?
Sep 29 2020
prev sibling parent reply Mike <slavo5150 yahoo.com> writes:
On Monday, 28 September 2020 at 19:55:10 UTC, Andrei Alexandrescu 
wrote:

 I'd love to get a better idea about this, e.g. a few clear 
 examples of bad uses and other few good examples where it's a 
 win. My intuition vaguely revolves around "aliasing to an 
 rvalue is bad and lvalue is good" but I year for clarity.
What's good about `alias this` ------------------------------ `alias this` is used for 2 primary purposes: 1. Forwarding a member's interface to its containing object's interface 2. Implicit casting and subtyping which are fundamentally different but with similar use cases ``` struct A { int x; } struct B { A a; alias a this; int y; } void PassA(A a) {} void main() { B b; int i = b.x; // A.x was forwarded through B int j = b.y; PassA(b); // B was implicitly cast to A } ``` `alias this` is actually useless for classes, because the same thing can be achieved with inheritance: ``` class A { int x; } class B : A { int y; } void PassA(A a) {} void main() { auto b = new B(); int i = b.x; // A.x was forwarded through B int j = b.y; PassA(b); // B was implicitly cast to A } ``` What's bad about `alias this` ----------------------------- Walter addressed the problem with `alias this` here:
 If a class hierarchy has alias this, when does the compiler go 
 looking down the alias this, and when does it go looking at the 
 base class and interfaces? (Of course the base class can have 
 an alias this, and an alias this can have a base class.) You 
 have essentially *two* multiple inheritance systems in play at 
 the same time, each obeying different rules.
 Couple that with the current arbitrary random rules about how 
 alias this behaves for classes, and any coherent MI alias this 
 scheme would randomly break existing code.
In other words, its too complex, and adding multiple `alias this` would only compound that complexity. My 2 cents ---------- `alias this` is useless for classes unless users want to abuse it to create "dual" inheritance by both inheriting from another class, and `alias this` a member simultaneously. Just use inheritance. If you need multiple inheritance, inherit from multiple interfaces and use D's excellent metaprogramming facilities to auto-implement each interface, or auto-forward members that implement the interfaces. ``` interface A { property int x(); } mixin template Aimp() { property int x() { return 0; } } interface B { property int y(); } mixin template Bimp() { property int y() { return 0; } } class C : A, B { mixin Aimp; mixin Bimp; } void PassA(A a) {} void PassB(B b) {} void main() { auto c = new C(); int i = c.x; // A's implementation in C int j = c.y; // B's implementation in C PassA(c); // C implicitly cast to A PassB(c); // C implicitly cast to B } ``` Where `alias this` has no alternative for structs because structs cannot inherit and cannot implement interfaces. D has sufficient metaprogramming facilities to auto-forward members, but the missing piece is implicit casting. ``` mixin template Aimp() { int x; } mixin template Bimp() { int y; } struct C { mixin Aimp; mixin Bimp; } void PassA(A a) {} // Error: What do we put here when we want a type that implements `A`. There is no such type? void PassB(B b) {} // Error: What do we put here when we want a type that implements `B`, There is no such type? void main() { auto c = new C(); int i = c.x; // A's implementation in C int j = c.y; // B's implementation in C PassA(c); // Error: C cannot implicitly cast to A PassB(c); // Error: C canot implicitly cast to B } ``` So, here are a couple of proposals off the top of my head. I imagine someone more talented than I can think of a few more: 1. Deprecate `alias this` for classes, and implement multiple `alias this` for structs. That will give users the composition feature they need, and in addition, because structs cannot inherit, it removes the complexity Walter spoke of. 2. Add `opImplicit`, implicit copy constructors, or something of that ilk. Then users only need to forward members using D's metaprogramming facilities. Both uses of `alias this` are covered, but no `alias this` is required. `alias this` can then be deprecated entirely. 3. Add struct inheritance like C++.
Sep 29 2020
next sibling parent reply Mike <slavo5150 yahoo.com> writes:
On Wednesday, 30 September 2020 at 01:36:59 UTC, Mike wrote:

 So, here are a couple of proposals off the top of my head.  I 
 imagine someone more talented than I can think of a few more:

 1.  Deprecate `alias this` for classes, and implement multiple 
 `alias this` for structs.  That will give users the composition 
 feature they need, and in addition, because structs cannot 
 inherit, it removes the complexity Walter spoke of.

 2.  Add `opImplicit`, implicit copy constructors, or something 
 of that ilk.  Then users only need to forward members using D's 
 metaprogramming facilities.  Both uses of `alias this` are 
 covered, but no `alias this` is required.  `alias this` can 
 then be deprecated entirely.

 3.  Add struct inheritance like C++.
4. Somehow allow structs to implement interfaces.
Sep 29 2020
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 9/29/20 9:42 PM, Mike wrote:
 On Wednesday, 30 September 2020 at 01:36:59 UTC, Mike wrote:
 
 So, here are a couple of proposals off the top of my head.  I imagine 
 someone more talented than I can think of a few more:

 1.  Deprecate `alias this` for classes, and implement multiple `alias 
 this` for structs.  That will give users the composition feature they 
 need, and in addition, because structs cannot inherit, it removes the 
 complexity Walter spoke of.

 2.  Add `opImplicit`, implicit copy constructors, or something of that 
 ilk.  Then users only need to forward members using D's 
 metaprogramming facilities.  Both uses of `alias this` are covered, 
 but no `alias this` is required.  `alias this` can then be deprecated 
 entirely.

 3.  Add struct inheritance like C++.
4. Somehow allow structs to implement interfaces.
I'd love it if interfaces could implement methods. (All MI related issues are related to state, not implementation of methods.)
Sep 29 2020
next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 9/29/20 10:08 PM, Andrei Alexandrescu wrote:
 On 9/29/20 9:42 PM, Mike wrote:
 On Wednesday, 30 September 2020 at 01:36:59 UTC, Mike wrote:

 So, here are a couple of proposals off the top of my head.  I imagine 
 someone more talented than I can think of a few more:

 1.  Deprecate `alias this` for classes, and implement multiple `alias 
 this` for structs.  That will give users the composition feature they 
 need, and in addition, because structs cannot inherit, it removes the 
 complexity Walter spoke of.

 2.  Add `opImplicit`, implicit copy constructors, or something of 
 that ilk.  Then users only need to forward members using D's 
 metaprogramming facilities.  Both uses of `alias this` are covered, 
 but no `alias this` is required.  `alias this` can then be deprecated 
 entirely.

 3.  Add struct inheritance like C++.
4. Somehow allow structs to implement interfaces.
I'd love it if interfaces could implement methods. (All MI related issues are related to state, not implementation of methods.)
BTW forgot to mention - this is from the category of removing limitations.
Sep 29 2020
prev sibling parent reply Mike <slavo5150 yahoo.com> writes:
On Wednesday, 30 September 2020 at 02:08:17 UTC, Andrei 
Alexandrescu wrote:
 On 9/29/20 9:42 PM, Mike wrote:
 On Wednesday, 30 September 2020 at 01:36:59 UTC, Mike wrote:
 
 So, here are a couple of proposals off the top of my head.  I 
 imagine someone more talented than I can think of a few more:

 1.  Deprecate `alias this` for classes, and implement 
 multiple `alias this` for structs.  That will give users the 
 composition feature they need, and in addition, because 
 structs cannot inherit, it removes the complexity Walter 
 spoke of.

 2.  Add `opImplicit`, implicit copy constructors, or 
 something of that ilk.  Then users only need to forward 
 members using D's metaprogramming facilities.  Both uses of 
 `alias this` are covered, but no `alias this` is required.  
 `alias this` can then be deprecated entirely.

 3.  Add struct inheritance like C++.
4. Somehow allow structs to implement interfaces.
I'd love it if interfaces could implement methods. (All MI related issues are related to state, not implementation of methods.)
Interface Members": https://devblogs.microsoft.com/dotnet/default-implementations-in-interfaces/ However, the didn't finish the implementation and deferred this very important component: https://github.com/dotnet/csharplang/issues/2337 I've used this That being said, I think that is somewhat tangential to the topic of this thread which I argue can be boiled down to "multiple alias this (or some other feature) is needed to do composition well with structs".
Sep 29 2020
parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Sep 30, 2020 at 02:34:27AM +0000, Mike via Digitalmars-d wrote:
 On Wednesday, 30 September 2020 at 02:08:17 UTC, Andrei Alexandrescu wrote:
[...]
 I'd love it if interfaces could implement methods. (All MI related
 issues are related to state, not implementation of methods.)
Interface Members": https://devblogs.microsoft.com/dotnet/default-implementations-in-interfaces/ However, the didn't finish the implementation and deferred this very important component: https://github.com/dotnet/csharplang/issues/2337 I've used this feature quite a bit, but it's only mildly useful until
Don't we already have this in D? interface I { void method1(); // overridable method final void method2() {} // default method } class C : I { void method1() {} } Of course, currently method bodies in interfaces are only allowed when T -- My program has no bugs! Only undocumented features...
Sep 29 2020
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 9/30/20 12:12 AM, H. S. Teoh wrote:
 On Wed, Sep 30, 2020 at 02:34:27AM +0000, Mike via Digitalmars-d wrote:
 On Wednesday, 30 September 2020 at 02:08:17 UTC, Andrei Alexandrescu wrote:
[...]
 I'd love it if interfaces could implement methods. (All MI related
 issues are related to state, not implementation of methods.)
Interface Members": https://devblogs.microsoft.com/dotnet/default-implementations-in-interfaces/ However, the didn't finish the implementation and deferred this very important component: https://github.com/dotnet/csharplang/issues/2337 I've used this feature quite a bit, but it's only mildly useful until
Don't we already have this in D? interface I { void method1(); // overridable method final void method2() {} // default method } class C : I { void method1() {} } Of course, currently method bodies in interfaces are only allowed when
It looks like default method bodies are virtual and can be overridden. I sort of remember at least having discussions about doing something like this, but I don't think it ever happened. -Steve
Sep 29 2020
parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Sep 30, 2020 at 12:48:56AM -0400, Steven Schveighoffer via
Digitalmars-d wrote:
 On 9/30/20 12:12 AM, H. S. Teoh wrote:
 On Wednesday, 30 September 2020 at 02:08:17 UTC, Andrei Alexandrescu wrote:
[...]
 I'd love it if interfaces could implement methods. (All MI
 related issues are related to state, not implementation of
 methods.)
[...]
 Don't we already have this in D?
 
 	interface I {
 		void method1();	// overridable method
 		final void method2() {} // default method
 	}
 	class C : I {
 		void method1() {}
 	}
 
 Of course, currently method bodies in interfaces are only allowed

It looks like default method bodies are virtual and can be overridden. I sort of remember at least having discussions about doing something like this, but I don't think it ever happened.
[...] If we allow virtual non-abstract methods in interfaces, that would certainly be MI. Though I'm guessing some people won't be happy until interfaces also carry state... :-P T -- You are only young once, but you can stay immature indefinitely. -- azephrahel
Sep 29 2020
prev sibling next sibling parent rikki cattermole <rikki cattermole.co.nz> writes:
On 30/09/2020 2:42 PM, Mike wrote:
 4. Somehow allow structs to implement interfaces.
Alternatively signatures. A static interface that inherits from an implementation type like struct or class. https://gist.github.com/rikkimax/826e1c4deb531e8dd993815bf914acea#signatures
Sep 29 2020
prev sibling parent IGotD- <nise nise.com> writes:
On Wednesday, 30 September 2020 at 01:42:30 UTC, Mike wrote:
 4. Somehow allow structs to implement interfaces.
Wouldn't that mean a vtable and therefore a POD violation?
Sep 30 2020
prev sibling next sibling parent reply Paolo Invernizzi <paolo.invernizzi gmail.com> writes:
On Wednesday, 30 September 2020 at 01:36:59 UTC, Mike wrote:
 On Monday, 28 September 2020 at 19:55:10 UTC, Andrei 
 Alexandrescu wrote:

 1.  Deprecate `alias this` for classes, and implement multiple 
 `alias this` for structs.  That will give users the composition 
 feature they need, and in addition, because structs cannot 
 inherit, it removes the complexity Walter spoke of.
This! We've never used alias this for classes, I'm wondering if there's something like that in Phobos, or in other projects ...
Sep 30 2020
next sibling parent Simen =?UTF-8?B?S2rDpnLDpXM=?= <simen.kjaras gmail.com> writes:
On Wednesday, 30 September 2020 at 07:54:39 UTC, Paolo Invernizzi 
wrote:
 On Wednesday, 30 September 2020 at 01:36:59 UTC, Mike wrote:
 On Monday, 28 September 2020 at 19:55:10 UTC, Andrei 
 Alexandrescu wrote:

 1.  Deprecate `alias this` for classes, and implement multiple 
 `alias this` for structs.  That will give users the 
 composition feature they need, and in addition, because 
 structs cannot inherit, it removes the complexity Walter spoke 
 of.
This! We've never used alias this for classes, I'm wondering if there's something like that in Phobos, or in other projects ...
There's quite a few tests in Phobos for alias this on classes, but I wasn't able to find a single feature that uses this (and frankly, I'd be surprised if I did). -- Simen
Sep 30 2020
prev sibling next sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Sep 30, 2020 at 07:54:39AM +0000, Paolo Invernizzi via Digitalmars-d
wrote:
 On Wednesday, 30 September 2020 at 01:36:59 UTC, Mike wrote:
 On Monday, 28 September 2020 at 19:55:10 UTC, Andrei Alexandrescu wrote:
 
 1.  Deprecate `alias this` for classes, and implement multiple
 `alias this` for structs.  That will give users the composition
 feature they need, and in addition, because structs cannot inherit,
 it removes the complexity Walter spoke of.
This! We've never used alias this for classes, I'm wondering if there's something like that in Phobos, or in other projects ...
[...] I haven't used alias on classes either, but I did frequently use alias this on structs that wrap classes. Which may lead to some of the same complexity: struct S implicitly converts to class C which may in turn implicitly convert to base class B or interface I. But probably not as horrible as using alias this inside a class. T -- Three out of two people have difficulties with fractions. -- Dirk Eddelbuettel
Sep 30 2020
parent reply Paolo Invernizzi <paolo.invernizzi gmail.com> writes:
On Wednesday, 30 September 2020 at 12:34:03 UTC, H. S. Teoh wrote:
 On Wed, Sep 30, 2020 at 07:54:39AM +0000, Paolo Invernizzi via 
 Digitalmars-d wrote:
 On Wednesday, 30 September 2020 at 01:36:59 UTC, Mike wrote:
 On Monday, 28 September 2020 at 19:55:10 UTC, Andrei 
 Alexandrescu wrote:
 
 1.  Deprecate `alias this` for classes, and implement 
 multiple `alias this` for structs.  That will give users the 
 composition feature they need, and in addition, because 
 structs cannot inherit, it removes the complexity Walter 
 spoke of.
This! We've never used alias this for classes, I'm wondering if there's something like that in Phobos, or in other projects ...
[...] I haven't used alias on classes either, but I did frequently use alias this on structs that wrap classes. Which may lead to some of the same complexity: struct S implicitly converts to class C which may in turn implicitly convert to base class B or interface I. But probably not as horrible as using alias this inside a class. T
Indeed, I imagine that's a much simpler case to handle in the compiler. It would be interesting to have a PR that disable alias this for classes just to have a look on how many external dub projects are impacted by that ...
Sep 30 2020
next sibling parent mw <mingwu gmail.com> writes:
On Wednesday, 30 September 2020 at 12:40:03 UTC, Paolo Invernizzi 
wrote:
 On Wednesday, 30 September 2020 at 12:34:03 UTC, H. S. Teoh 
 wrote:
 On Wed, Sep 30, 2020 at 07:54:39AM +0000, Paolo Invernizzi via 
 Digitalmars-d wrote:
 On Wednesday, 30 September 2020 at 01:36:59 UTC, Mike wrote:
 On Monday, 28 September 2020 at 19:55:10 UTC, Andrei 
 Alexandrescu wrote:
 
 1.  Deprecate `alias this` for classes, and implement 
 multiple `alias this` for structs.  That will give users 
 the composition feature they need, and in addition, because 
 structs cannot inherit, it removes the complexity Walter 
 spoke of.
This! We've never used alias this for classes, I'm wondering if there's something like that in Phobos, or in other projects ...
 It would be interesting to have a PR that disable alias this 
 for classes just to have a look on how many external dub 
 projects are impacted by that ...
Right, we just had a discussion last month on the problems I found here: https://forum.dlang.org/post/pjxwebeyiypgtgxqmcdp forum.dlang.org class SharedArray(T) { public T[] array; alias array this; // subtyping } The point is, these D language features are not well-thought and designed, and when people start to use it and mix with other language features, all kinds of weird corner-case behavior show up and surprise the user.
Sep 30 2020
prev sibling parent Mike <slavo5150 yahoo.com> writes:
On Wednesday, 30 September 2020 at 12:40:03 UTC, Paolo Invernizzi 
wrote:

 Indeed, I imagine that's a much simpler case to handle in the 
 compiler.

 It would be interesting to have a PR that disable alias this 
 for classes just to have a look on how many external dub 
 projects are impacted by that ...
https://github.com/dlang/dmd/pull/11817
Sep 30 2020
prev sibling parent reply Mike <slavo5150 yahoo.com> writes:
On Wednesday, 30 September 2020 at 07:54:39 UTC, Paolo Invernizzi 
wrote:
 On Wednesday, 30 September 2020 at 01:36:59 UTC, Mike wrote:
 1.  Deprecate `alias this` for classes, and implement multiple 
 `alias this` for structs.  That will give users the 
 composition feature they need, and in addition, because 
 structs cannot inherit, it removes the complexity Walter spoke 
 of.
This! We've never used alias this for classes, I'm wondering if there's something like that in Phobos, or in other projects ...
To be more precise, you don't actually have to deprecated alias this for classes. You could keep singular alias this for classes and then add multiple alias this for structs. That may satisfy the "add, don't change" crowd, while still giving users the struct composition features that D currently lacks.
Sep 30 2020
parent Carl Sturtivant <sturtivant gmail.com> writes:
On Thursday, 1 October 2020 at 00:40:05 UTC, Mike wrote:
 To be more precise, you don't actually have to deprecated alias 
 this for classes.  You could keep singular alias this for 
 classes and then add multiple alias this for structs.  That may 
 satisfy the "add, don't change" crowd, while still giving users 
 the struct composition features that D currently lacks.
Yes, an extension for structs only seems like a good way to avoid adding edge cases. Here's a suggestion. https://forum.dlang.org/thread/uniyvmvjopeyyxmphfso forum.dlang.org
Aug 05 2021
prev sibling parent IGotD- <nise nise.com> writes:
On Wednesday, 30 September 2020 at 01:36:59 UTC, Mike wrote:
 1.  Deprecate `alias this` for classes, and implement multiple 
 `alias this` for structs.  That will give users the composition 
 feature they need, and in addition, because structs cannot 
 inherit, it removes the complexity Walter spoke of.

 2.  Add `opImplicit`, implicit copy constructors, or something 
 of that ilk.  Then users only need to forward members using D's 
 metaprogramming facilities.  Both uses of `alias this` are 
 covered, but no `alias this` is required.  `alias this` can 
 then be deprecated entirely.

 3.  Add struct inheritance like C++.
4. Remove "alias this" completely, use mixin templates instead. I originally misunderstood template mixins believing it was more or less just expansion into the scope. It turns out that there is a lot more going on under the hood, which makes the template mixin work like inheritance. This currently badly documented which makes people believe that template mixins are more limited.
Sep 30 2020
prev sibling parent reply IGotD- <nise nise.com> writes:
On Monday, 28 September 2020 at 18:44:51 UTC, H. S. Teoh wrote:
 `alias this` is one of the things that seemed like a good idea 
 at the time, but is turning out to be something that leads to 
 code smells.  If anything, we'd like to get rid of it rather 
 than extend it!


 T
As it seems, the language maintainers want to remove alias this totally. If that's the case shouldn't the documentation be updated telling the programmers that if they write new code they should avoid alias this, and then also direct them to alternative solutions.
Sep 29 2020
parent reply IGotD- <nise nise.com> writes:
On Tuesday, 29 September 2020 at 09:21:42 UTC, IGotD- wrote:
 On Monday, 28 September 2020 at 18:44:51 UTC, H. S. Teoh wrote:
 `alias this` is one of the things that seemed like a good idea 
 at the time, but is turning out to be something that leads to 
 code smells.  If anything, we'd like to get rid of it rather 
 than extend it!


 T
As it seems, the language maintainers want to remove alias this totally. If that's the case shouldn't the documentation be updated telling the programmers that if they write new code they should avoid alias this, and then also direct them to alternative solutions.
Further more, this in the "alias this" documentation. "Multiple AliasThis are allowed. For implicit conversions and forwarded lookups, all AliasThis declarations are attempted; if more than one AliasThis is eligible, the ambiguity is disallowed by raising an error. Note: Multiple AliasThis is currently unimplemented." which is totally out of date, needs to be removed. Further more, there seems to be some magic going on with mixin templates when it comes to constructors and deconstructors. This is not documented.
Sep 29 2020
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 9/29/20 2:37 PM, IGotD- wrote:
 On Tuesday, 29 September 2020 at 09:21:42 UTC, IGotD- wrote:
 On Monday, 28 September 2020 at 18:44:51 UTC, H. S. Teoh wrote:
 `alias this` is one of the things that seemed like a good idea at the 
 time, but is turning out to be something that leads to code smells.  
 If anything, we'd like to get rid of it rather than extend it!


 T
As it seems, the language maintainers want to remove alias this totally. If that's the case shouldn't the documentation be updated telling the programmers that if they write new code they should avoid alias this, and then also direct them to alternative solutions.
Further more, this in the "alias this" documentation. "Multiple AliasThis are allowed. For implicit conversions and forwarded lookups, all AliasThis declarations are attempted; if more than one AliasThis is eligible, the ambiguity is disallowed by raising an error. Note: Multiple AliasThis is currently unimplemented." which is totally out of date, needs to be removed.
Ouch. A PR to change that would be in order regardless of future actions.
Sep 29 2020
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 9/29/20 8:46 PM, Andrei Alexandrescu wrote:
 On 9/29/20 2:37 PM, IGotD- wrote:
 On Tuesday, 29 September 2020 at 09:21:42 UTC, IGotD- wrote:
 On Monday, 28 September 2020 at 18:44:51 UTC, H. S. Teoh wrote:
 `alias this` is one of the things that seemed like a good idea at 
 the time, but is turning out to be something that leads to code 
 smells. If anything, we'd like to get rid of it rather than extend it!


 T
As it seems, the language maintainers want to remove alias this totally. If that's the case shouldn't the documentation be updated telling the programmers that if they write new code they should avoid alias this, and then also direct them to alternative solutions.
Further more, this in the "alias this" documentation. "Multiple AliasThis are allowed. For implicit conversions and forwarded lookups, all AliasThis declarations are attempted; if more than one AliasThis is eligible, the ambiguity is disallowed by raising an error. Note: Multiple AliasThis is currently unimplemented." which is totally out of date, needs to be removed.
Ouch. A PR to change that would be in order regardless of future actions.
Time waits for no one. https://github.com/dlang/dlang.org/pull/2862
Sep 29 2020
prev sibling parent mw <mingwu gmail.com> writes:
On Monday, 28 September 2020 at 18:13:15 UTC, H. S. Teoh wrote:
 On Mon, Sep 28, 2020 at 05:59:19PM +0000, mw via Digitalmars-d 
 wrote:
 I think this deserved to be better known:
 
 The diamond problem is a *solved* problem by Eiffel language, 
 which won the 2006 ACM Software System Award:
 
 https://en.wikipedia.org/wiki/ACM_Software_System_Award
That award has nothing to do with the diamond problem. There is nothing in the link that even mentions the diamond problem.
The two hallmarks of Eiffel, is design-by-contract and multiple inheritance, which is known in academics (in my former life). it's a pity that D only picked design-by-contract from Eiffel, but throw away multiple inheritance, ... and instead introduced sub-typing, mixin, which Walter said: https://forum.dlang.org/post/rb4seo$bfm$1 digitalmars.com """ The trouble was, it was inserted without realizing it was multiple inheritance, meaning its behaviors are ad-hoc and don't make a whole lot of sense when examined carefully. """ If we really want to fix it, can do it in D3.
Sep 28 2020