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 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