www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - DIP66 1.2 (Multiple) alias this. Continuation of work.

reply "IgorStepanov" <wazar mail.ru> writes:
http://wiki.dlang.org/DIP66

First I want to apologize for the long absence.
I was very busy for those months and now I ready to continue the 
work.

This DIP has been approved with three clarifications:
about is-expression, about opDispatch and about "common" 
inheritance.
I've reflected those clarifications in this DIP version, and if 
it is OK, I'll start adaptation of my github PR to this DIP.
Mar 28 2015
next sibling parent "Brad Anderson" <eco gnuk.net> writes:
On Saturday, 28 March 2015 at 19:52:15 UTC, IgorStepanov wrote:
 http://wiki.dlang.org/DIP66

 First I want to apologize for the long absence.
 I was very busy for those months and now I ready to continue 
 the work.

 This DIP has been approved with three clarifications:
 about is-expression, about opDispatch and about "common" 
 inheritance.
 I've reflected those clarifications in this DIP version, and if 
 it is OK, I'll start adaptation of my github PR to this DIP.
You're awesome, Igor. Thanks for taking on hard problems.
Mar 28 2015
prev sibling parent reply "deadalnix" <deadalnix gmail.com> writes:
On Saturday, 28 March 2015 at 19:52:15 UTC, IgorStepanov wrote:
 http://wiki.dlang.org/DIP66

 First I want to apologize for the long absence.
 I was very busy for those months and now I ready to continue 
 the work.

 This DIP has been approved with three clarifications:
 about is-expression, about opDispatch and about "common" 
 inheritance.
 I've reflected those clarifications in this DIP version, and if 
 it is OK, I'll start adaptation of my github PR to this DIP.
Can you explain the change from current situation a bit ?
Mar 29 2015
parent reply "IgorStepanov" <wazar mail.ru> writes:
On Sunday, 29 March 2015 at 08:03:37 UTC, deadalnix wrote:
 On Saturday, 28 March 2015 at 19:52:15 UTC, IgorStepanov wrote:
 http://wiki.dlang.org/DIP66

 First I want to apologize for the long absence.
 I was very busy for those months and now I ready to continue 
 the work.

 This DIP has been approved with three clarifications:
 about is-expression, about opDispatch and about "common" 
 inheritance.
 I've reflected those clarifications in this DIP version, and 
 if it is OK, I'll start adaptation of my github PR to this DIP.
Can you explain the change from current situation a bit ?
Do you mean "changes from previous DIP version"? I've added three ideas to this version: 1. We should reject types which use opDispatch and alias this at the same time. 2. We want to semantic alias this at the same time as an inheritance (and disallow hidding of "alias this"-ed members by inherited members), but we shouldn't do this change now, because it may break a lot of existing code. 3. is(T: B) should raise an error if there are many ways to convert T to B. If you ask about changes from current alias this implementation, this DIP introduces multiple alias this, and formally discribes different cases.
Mar 29 2015
next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Sunday, 29 March 2015 at 17:34:21 UTC, IgorStepanov wrote:
 Do you mean "changes from previous DIP version"?
 I've added three ideas to this version:
 1. We should reject types which use opDispatch and alias this 
 at the same time.
That sound overly imitative, but I can roll with that :)
 2. We want to semantic alias this at the same time as an 
 inheritance (and disallow hidding of "alias this"-ed members by 
 inherited members), but we shouldn't do this change now, 
 because it may break a lot of existing code.
I struggled with defining that one, so that is a good thing.
 3. is(T: B) should raise an error if there are many ways to 
 convert T to B.
SDC already reject alias if there are various path that lead to the same type.
Mar 29 2015
prev sibling next sibling parent "extrawurst" <stephan extrawurst.org> writes:
On Sunday, 29 March 2015 at 17:34:21 UTC, IgorStepanov wrote:
 On Sunday, 29 March 2015 at 08:03:37 UTC, deadalnix wrote:
 On Saturday, 28 March 2015 at 19:52:15 UTC, IgorStepanov wrote:
 http://wiki.dlang.org/DIP66

 First I want to apologize for the long absence.
 I was very busy for those months and now I ready to continue 
 the work.

 This DIP has been approved with three clarifications:
 about is-expression, about opDispatch and about "common" 
 inheritance.
 I've reflected those clarifications in this DIP version, and 
 if it is OK, I'll start adaptation of my github PR to this 
 DIP.
Can you explain the change from current situation a bit ?
Do you mean "changes from previous DIP version"? I've added three ideas to this version: 1. We should reject types which use opDispatch and alias this at the same time.
thats ok - I can use multiple alias this then to delegate to types that use opDispatch, right ? :P
 2. We want to semantic alias this at the same time as an 
 inheritance (and disallow hidding of "alias this"-ed members by 
 inherited members), but we shouldn't do this change now, 
 because it may break a lot of existing code.
 3. is(T: B) should raise an error if there are many ways to 
 convert T to B.

 If you ask about changes from current alias this 
 implementation, this DIP introduces multiple alias this, and 
 formally discribes different cases.
Mar 29 2015
prev sibling next sibling parent Jacob Carlborg <doob me.com> writes:
On 2015-03-29 19:34, IgorStepanov wrote:

 1. We should reject types which use opDispatch and alias this at the
 same time.
Isn't there a well defined order these features apply in? -- /Jacob Carlborg
Mar 29 2015
prev sibling next sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 3/29/15 1:34 PM, IgorStepanov wrote:

 1. We should reject types which use opDispatch and alias this at the
 same time.
Why? Alias this has no filter. opDispatch can use template constraints. It makes perfect sense to prefer opDispatch, unless it doesn't have a valid match, and then use alias this instead. For example, if I wanted to wrap a type so I can instrument calls to 'foo', I could do something like this: struct FooWrapper(T) { T t; alias t this; auto opDispatch(string s, A...)(A args) if(s == "foo") { writeln("calling foo"); return t.foo(args); } } Why is this a bad use case? -Steve
Mar 30 2015
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 3/30/15 8:04 AM, Steven Schveighoffer wrote:
 On 3/29/15 1:34 PM, IgorStepanov wrote:

 1. We should reject types which use opDispatch and alias this at the
 same time.
Why? Alias this has no filter. opDispatch can use template constraints. It makes perfect sense to prefer opDispatch, unless it doesn't have a valid match, and then use alias this instead. For example, if I wanted to wrap a type so I can instrument calls to 'foo', I could do something like this: struct FooWrapper(T) { T t; alias t this; auto opDispatch(string s, A...)(A args) if(s == "foo") { writeln("calling foo"); return t.foo(args); } } Why is this a bad use case?
The idea is to start restrictive and define interaction meaningfully later based on compelling use cases. -- Andrei
Mar 30 2015
next sibling parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 3/30/15 2:33 PM, Andrei Alexandrescu wrote:
 On 3/30/15 8:04 AM, Steven Schveighoffer wrote:
 On 3/29/15 1:34 PM, IgorStepanov wrote:

 1. We should reject types which use opDispatch and alias this at the
 same time.
Why? Alias this has no filter. opDispatch can use template constraints. It makes perfect sense to prefer opDispatch, unless it doesn't have a valid match, and then use alias this instead. For example, if I wanted to wrap a type so I can instrument calls to 'foo', I could do something like this: struct FooWrapper(T) { T t; alias t this; auto opDispatch(string s, A...)(A args) if(s == "foo") { writeln("calling foo"); return t.foo(args); } } Why is this a bad use case?
The idea is to start restrictive and define interaction meaningfully later based on compelling use cases. -- Andrei
Something tells me you don't think this is compelling. I do. Any kind of wrapper type that intends to override some category of behavior is going to want to do this. Currently, we are stuck with opDispatch-ing all members, including fields. It is also currently valid to use alias this solely as a cast, and use opDispatch to define the API. Outlawing these being used together would break any code relying on that. BTW, if there is a clear and obvious way to define this, why are we willfully ignoring it? What is the downside of my use case? -Steve
Mar 30 2015
prev sibling parent reply "IgorStepanov" <wazar mail.ru> writes:
On Monday, 30 March 2015 at 18:33:17 UTC, Andrei Alexandrescu 
wrote:
 On 3/30/15 8:04 AM, Steven Schveighoffer wrote:
 On 3/29/15 1:34 PM, IgorStepanov wrote:

 1. We should reject types which use opDispatch and alias this 
 at the
 same time.
Why? Alias this has no filter. opDispatch can use template constraints. It makes perfect sense to prefer opDispatch, unless it doesn't have a valid match, and then use alias this instead. For example, if I wanted to wrap a type so I can instrument calls to 'foo', I could do something like this: struct FooWrapper(T) { T t; alias t this; auto opDispatch(string s, A...)(A args) if(s == "foo") { writeln("calling foo"); return t.foo(args); } } Why is this a bad use case?
The idea is to start restrictive and define interaction meaningfully later based on compelling use cases. -- Andrei
Andrei, do you approve those changes? Can we move to work on my github PR?
Mar 31 2015
next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 3/31/15 7:28 AM, IgorStepanov wrote:
 On Monday, 30 March 2015 at 18:33:17 UTC, Andrei Alexandrescu wrote:
 On 3/30/15 8:04 AM, Steven Schveighoffer wrote:
 On 3/29/15 1:34 PM, IgorStepanov wrote:

 1. We should reject types which use opDispatch and alias this at the
 same time.
Why? Alias this has no filter. opDispatch can use template constraints. It makes perfect sense to prefer opDispatch, unless it doesn't have a valid match, and then use alias this instead. For example, if I wanted to wrap a type so I can instrument calls to 'foo', I could do something like this: struct FooWrapper(T) { T t; alias t this; auto opDispatch(string s, A...)(A args) if(s == "foo") { writeln("calling foo"); return t.foo(args); } } Why is this a bad use case?
The idea is to start restrictive and define interaction meaningfully later based on compelling use cases. -- Andrei
Andrei, do you approve those changes? Can we move to work on my github PR?
Gotta run for a couple hours, will review this shortly after. -- Andrei
Mar 31 2015
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 3/31/15 7:28 AM, IgorStepanov wrote:
 On Monday, 30 March 2015 at 18:33:17 UTC, Andrei Alexandrescu wrote:
 On 3/30/15 8:04 AM, Steven Schveighoffer wrote:
 On 3/29/15 1:34 PM, IgorStepanov wrote:

 1. We should reject types which use opDispatch and alias this at the
 same time.
Why? Alias this has no filter. opDispatch can use template constraints. It makes perfect sense to prefer opDispatch, unless it doesn't have a valid match, and then use alias this instead. For example, if I wanted to wrap a type so I can instrument calls to 'foo', I could do something like this: struct FooWrapper(T) { T t; alias t this; auto opDispatch(string s, A...)(A args) if(s == "foo") { writeln("calling foo"); return t.foo(args); } } Why is this a bad use case?
The idea is to start restrictive and define interaction meaningfully later based on compelling use cases. -- Andrei
Andrei, do you approve those changes? Can we move to work on my github PR?
I made a few editorial passes, no major changes. I think there's still a fly in the ointment. The resolution algorithm goes: 1. If xyz is a symbol (member, method, enum etc) defined inside typeof(obj) then lookup is done. 2. Otherwise, if xyz is a symbol introduced in the base class (where applicable), then lookup is done. 3. Otherwise, if opDispatch!"xyz" exists, then lookup is done. 4. Otherwise, alias this is attempted transitively, and if xyz is found, then lookup is done. 5. Otherwise an UFCS rewrite is effected. This puts opDispatch in between inheritance and subtyping, which I think we discussed is inappropriate - alias this should be effectively subtyping. If we're really convinced alias this means multiple subtyping, the inherited type should not have a special role. However, it simplifies a lot of things to give one particular subtype a leg up on all others. So I think this would work: 1. If xyz is a symbol (member, method, enum etc) defined inside typeof(obj) then lookup is done. 2. Otherwise, if xyz is a symbol introduced in the base class (where applicable), then lookup is done. 3. Otherwise, if xyz is found at least via either an opDispatch!"xyz" or alias this conversion, then lookup is done. 4. Otherwise an UFCS rewrite is effected. Then you explain that if you find more than one possibility via opDispatch and alias this, that's an ambiguity error. I noticed you do mention in the Limitations section that opDispatch and alias this cannot be simultaneously present, but that kind of contradicts your resolution algorithm. Andrei
Mar 31 2015
next sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 3/31/15 4:01 PM, Andrei Alexandrescu wrote:
 On 3/31/15 7:28 AM, IgorStepanov wrote:
 On Monday, 30 March 2015 at 18:33:17 UTC, Andrei Alexandrescu wrote:
 On 3/30/15 8:04 AM, Steven Schveighoffer wrote:
 On 3/29/15 1:34 PM, IgorStepanov wrote:

 1. We should reject types which use opDispatch and alias this at the
 same time.
Why? Alias this has no filter. opDispatch can use template constraints. It makes perfect sense to prefer opDispatch, unless it doesn't have a valid match, and then use alias this instead. For example, if I wanted to wrap a type so I can instrument calls to 'foo', I could do something like this: struct FooWrapper(T) { T t; alias t this; auto opDispatch(string s, A...)(A args) if(s == "foo") { writeln("calling foo"); return t.foo(args); } } Why is this a bad use case?
The idea is to start restrictive and define interaction meaningfully later based on compelling use cases. -- Andrei
Andrei, do you approve those changes? Can we move to work on my github PR?
I made a few editorial passes, no major changes. I think there's still a fly in the ointment. The resolution algorithm goes: 1. If xyz is a symbol (member, method, enum etc) defined inside typeof(obj) then lookup is done. 2. Otherwise, if xyz is a symbol introduced in the base class (where applicable), then lookup is done. 3. Otherwise, if opDispatch!"xyz" exists, then lookup is done. 4. Otherwise, alias this is attempted transitively, and if xyz is found, then lookup is done. 5. Otherwise an UFCS rewrite is effected.
swap 2 and 3.
 This puts opDispatch in between inheritance and subtyping, which I think
 we discussed is inappropriate - alias this should be effectively subtyping.
I don't understand this statement. What is the difference between inheritance and subtyping? To me, opDispatch is equivalent to adding a member function (with specific members overriding opDispatch), alias this is equivalent to inheriting from another type (with inherited members overriding alias this). And I still think that alias this + opDispatch conflicts should defer to opDispatch. It makes no sense to do it any other way. -Steve
Mar 31 2015
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 3/31/15 1:20 PM, Steven Schveighoffer wrote:
 On 3/31/15 4:01 PM, Andrei Alexandrescu wrote:
 On 3/31/15 7:28 AM, IgorStepanov wrote:
 On Monday, 30 March 2015 at 18:33:17 UTC, Andrei Alexandrescu wrote:
 On 3/30/15 8:04 AM, Steven Schveighoffer wrote:
 On 3/29/15 1:34 PM, IgorStepanov wrote:

 1. We should reject types which use opDispatch and alias this at the
 same time.
Why? Alias this has no filter. opDispatch can use template constraints. It makes perfect sense to prefer opDispatch, unless it doesn't have a valid match, and then use alias this instead. For example, if I wanted to wrap a type so I can instrument calls to 'foo', I could do something like this: struct FooWrapper(T) { T t; alias t this; auto opDispatch(string s, A...)(A args) if(s == "foo") { writeln("calling foo"); return t.foo(args); } } Why is this a bad use case?
The idea is to start restrictive and define interaction meaningfully later based on compelling use cases. -- Andrei
Andrei, do you approve those changes? Can we move to work on my github PR?
I made a few editorial passes, no major changes. I think there's still a fly in the ointment. The resolution algorithm goes: 1. If xyz is a symbol (member, method, enum etc) defined inside typeof(obj) then lookup is done. 2. Otherwise, if xyz is a symbol introduced in the base class (where applicable), then lookup is done. 3. Otherwise, if opDispatch!"xyz" exists, then lookup is done. 4. Otherwise, alias this is attempted transitively, and if xyz is found, then lookup is done. 5. Otherwise an UFCS rewrite is effected.
swap 2 and 3.
That would break code and again it's contradicted by restrictions mentioned below. No need to make the DIP overly complicated.
 This puts opDispatch in between inheritance and subtyping, which I think
 we discussed is inappropriate - alias this should be effectively
 subtyping.
I don't understand this statement. What is the difference between inheritance and subtyping?
Inheritance is only one of the forms of subtyping.
 To me, opDispatch is equivalent to adding a member function (with
 specific members overriding opDispatch), alias this is equivalent to
 inheriting from another type (with inherited members overriding alias
 this).

 And I still think that alias this + opDispatch conflicts should defer to
 opDispatch. It makes no sense to do it any other way.
Again: start conservative, loose screws later. No regrets. Andrei
Mar 31 2015
prev sibling next sibling parent Jacob Carlborg <doob me.com> writes:
On 2015-03-31 22:01, Andrei Alexandrescu wrote:

 I made a few editorial passes, no major changes. I think there's still a
 fly in the ointment. The resolution algorithm goes:

 1. If xyz is a symbol (member, method, enum etc) defined inside
 typeof(obj) then lookup is done.
 2. Otherwise, if xyz is a symbol introduced in the base class (where
 applicable), then lookup is done.
 3. Otherwise, if opDispatch!"xyz" exists, then lookup is done.
 4. Otherwise, alias this is attempted transitively, and if xyz is found,
 then lookup is done.
 5. Otherwise an UFCS rewrite is effected.

 This puts opDispatch in between inheritance and subtyping, which I think
 we discussed is inappropriate - alias this should be effectively subtyping.

 If we're really convinced alias this means multiple subtyping, the
 inherited type should not have a special role. However, it simplifies a
 lot of things to give one particular subtype a leg up on all others. So
 I think this would work:

 1. If xyz is a symbol (member, method, enum etc) defined inside
 typeof(obj) then lookup is done.
 2. Otherwise, if xyz is a symbol introduced in the base class (where
 applicable), then lookup is done.
 3. Otherwise, if xyz is found at least via either an opDispatch!"xyz" or
 alias this conversion, then lookup is done.
 4. Otherwise an UFCS rewrite is effected.
Should opDispatch or "alias this" ever be looked up in the base class? -- /Jacob Carlborg
Mar 31 2015
prev sibling parent reply "IgorStepanov" <wazar mail.ru> writes:
On Tuesday, 31 March 2015 at 20:01:14 UTC, Andrei Alexandrescu 
wrote:
 On 3/31/15 7:28 AM, IgorStepanov wrote:
 On Monday, 30 March 2015 at 18:33:17 UTC, Andrei Alexandrescu 
 wrote:
 On 3/30/15 8:04 AM, Steven Schveighoffer wrote:
 On 3/29/15 1:34 PM, IgorStepanov wrote:

 1. We should reject types which use opDispatch and alias 
 this at the
 same time.
Why? Alias this has no filter. opDispatch can use template constraints. It makes perfect sense to prefer opDispatch, unless it doesn't have a valid match, and then use alias this instead. For example, if I wanted to wrap a type so I can instrument calls to 'foo', I could do something like this: struct FooWrapper(T) { T t; alias t this; auto opDispatch(string s, A...)(A args) if(s == "foo") { writeln("calling foo"); return t.foo(args); } } Why is this a bad use case?
The idea is to start restrictive and define interaction meaningfully later based on compelling use cases. -- Andrei
Andrei, do you approve those changes? Can we move to work on my github PR?
I made a few editorial passes, no major changes. I think there's still a fly in the ointment. The resolution algorithm goes: 1. If xyz is a symbol (member, method, enum etc) defined inside typeof(obj) then lookup is done. 2. Otherwise, if xyz is a symbol introduced in the base class (where applicable), then lookup is done. 3. Otherwise, if opDispatch!"xyz" exists, then lookup is done. 4. Otherwise, alias this is attempted transitively, and if xyz is found, then lookup is done. 5. Otherwise an UFCS rewrite is effected. This puts opDispatch in between inheritance and subtyping, which I think we discussed is inappropriate - alias this should be effectively subtyping. If we're really convinced alias this means multiple subtyping, the inherited type should not have a special role. However, it simplifies a lot of things to give one particular subtype a leg up on all others. So I think this would work: 1. If xyz is a symbol (member, method, enum etc) defined inside typeof(obj) then lookup is done. 2. Otherwise, if xyz is a symbol introduced in the base class (where applicable), then lookup is done. 3. Otherwise, if xyz is found at least via either an opDispatch!"xyz" or alias this conversion, then lookup is done. 4. Otherwise an UFCS rewrite is effected. Then you explain that if you find more than one possibility via opDispatch and alias this, that's an ambiguity error. I noticed you do mention in the Limitations section that opDispatch and alias this cannot be simultaneously present, but that kind of contradicts your resolution algorithm. Andrei
Ok, I've applied your changes to the DIP page, and I'm starting to rework my github PR. Sorry for the slow work (I'm very busy last time). However I still working. Stay on line=)
May 25 2015
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 5/25/15 3:01 PM, IgorStepanov wrote:
 Ok, I've applied your changes to the DIP page, and I'm starting to
 rework my github PR. Sorry for the slow work (I'm very busy last time).
 However I still working. Stay on line=)
Thanks. Please get this done and let's pull it in for 068. -- Andrei
May 25 2015
parent reply "IgorStepanov" <wazar mail.ru> writes:
On Tuesday, 26 May 2015 at 00:03:43 UTC, Andrei Alexandrescu 
wrote:
 On 5/25/15 3:01 PM, IgorStepanov wrote:
 Ok, I've applied your changes to the DIP page, and I'm 
 starting to
 rework my github PR. Sorry for the slow work (I'm very busy 
 last time).
 However I still working. Stay on line=)
Thanks. Please get this done and let's pull it in for 068. -- Andrei
I've finished preparing of the github PR. Now it is ready for review.
May 29 2015
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 5/29/15 3:37 PM, IgorStepanov wrote:
 On Tuesday, 26 May 2015 at 00:03:43 UTC, Andrei Alexandrescu wrote:
 On 5/25/15 3:01 PM, IgorStepanov wrote:
 Ok, I've applied your changes to the DIP page, and I'm starting to
 rework my github PR. Sorry for the slow work (I'm very busy last time).
 However I still working. Stay on line=)
Thanks. Please get this done and let's pull it in for 068. -- Andrei
I've finished preparing of the github PR. Now it is ready for review.
So https://github.com/D-Programming-Language/dmd/pull/3998 is the one? -- Andrei
May 29 2015
next sibling parent "IgorStepanov" <wazar mail.ru> writes:
On Friday, 29 May 2015 at 21:41:12 UTC, Andrei Alexandrescu wrote:
 On 5/29/15 3:37 PM, IgorStepanov wrote:
 On Tuesday, 26 May 2015 at 00:03:43 UTC, Andrei Alexandrescu 
 wrote:
 On 5/25/15 3:01 PM, IgorStepanov wrote:
 Ok, I've applied your changes to the DIP page, and I'm 
 starting to
 rework my github PR. Sorry for the slow work (I'm very busy 
 last time).
 However I still working. Stay on line=)
Thanks. Please get this done and let's pull it in for 068. -- Andrei
I've finished preparing of the github PR. Now it is ready for review.
So https://github.com/D-Programming-Language/dmd/pull/3998 is the one? -- Andrei
Yep.
May 29 2015
prev sibling parent "IgorStepanov" <wazar mail.ru> writes:
Hello, comrades. Lets put into the schedule reviewing of this PR 
(https://github.com/D-Programming-Language/dmd/pull/3998).
It contains a very much changes and it is hard to maintain its 
performance: each foreign PR may break it.
Jun 04 2015
prev sibling parent reply "IgorStepanov" <wazar mail.ru> writes:
On Monday, 30 March 2015 at 15:04:20 UTC, Steven Schveighoffer 
wrote:
 On 3/29/15 1:34 PM, IgorStepanov wrote:

 1. We should reject types which use opDispatch and alias this 
 at the
 same time.
Why? Alias this has no filter. opDispatch can use template constraints. It makes perfect sense to prefer opDispatch, unless it doesn't have a valid match, and then use alias this instead. For example, if I wanted to wrap a type so I can instrument calls to 'foo', I could do something like this: struct FooWrapper(T) { T t; alias t this; auto opDispatch(string s, A...)(A args) if(s == "foo") { writeln("calling foo"); return t.foo(args); } } Why is this a bad use case? -Steve
You can split this code to two structs: struct FooWrapper(T) { struct FooDispatcher { auto opDispatch(string s, A...)(A args) { writeln("calling ", s); } } FooDispatcher d; T t; alias t this; auto foo(string s, A...)(A args) { writeln("calling foo"); return t.foo(args); } } FooWrapper!X x; x.foo(1, 2); //FooWrapper.foo has been called x.bar(1, 2); //FooWrapper.d.opDispatch has been called X orig = x; //FooWrepper.t is returned. =============== Yes, this code is much more tricky, but it work as you wish. opDispatch + alias this may deliver many problems, if one of those has more high priority then the other. We want to implement alias this maximally strictly, and after that, try to find rules which may be safely relaxed.
Mar 30 2015
parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 3/30/15 3:19 PM, IgorStepanov wrote:
 On Monday, 30 March 2015 at 15:04:20 UTC, Steven Schveighoffer wrote:
 On 3/29/15 1:34 PM, IgorStepanov wrote:

 1. We should reject types which use opDispatch and alias this at the
 same time.
Why? Alias this has no filter. opDispatch can use template constraints. It makes perfect sense to prefer opDispatch, unless it doesn't have a valid match, and then use alias this instead. For example, if I wanted to wrap a type so I can instrument calls to 'foo', I could do something like this: struct FooWrapper(T) { T t; alias t this; auto opDispatch(string s, A...)(A args) if(s == "foo") { writeln("calling foo"); return t.foo(args); } } Why is this a bad use case? -Steve
You can split this code to two structs: struct FooWrapper(T) { struct FooDispatcher { auto opDispatch(string s, A...)(A args) { writeln("calling ", s); } } FooDispatcher d; T t; alias t this; auto foo(string s, A...)(A args) { writeln("calling foo"); return t.foo(args); } } FooWrapper!X x; x.foo(1, 2); //FooWrapper.foo has been called x.bar(1, 2); //FooWrapper.d.opDispatch has been called X orig = x; //FooWrepper.t is returned. =============== Yes, this code is much more tricky, but it work as you wish. opDispatch + alias this may deliver many problems, if one of those has more high priority then the other. We want to implement alias this maximally strictly, and after that, try to find rules which may be safely relaxed.
Not exactly. Yes, you have successfully pointed out that using opDispatch to define one named method is sort of useless, but that was not my point. Imagine if you wanted to do that to all methods that were in a list. I can imagine a use case that logs all calls to a type that are defined by a list: struct LogWrapper(T, string[] funcnames) { ... } It is impossible to do this generically and also use alias this. In today's situation, I can't override *selected* pieces of alias this, I must override all of them, because opDispatch takes precedence, even if there is no overriding. For example, this doesn't work: struct Wrapper(T) { T t; alias t this; auto opDispatch(string name, A...)(A args) if(name == "foo") { mixin("return t." ~ name ~ "(args);"); } } Call w.bar(), and even if T has a bar method, it fails to compile, because opDispatch *fully* eclipses alias this. Even fields cannot be accessed. However, alias this does still provide subtyping, I can call func(T t) with a Wrapper!T. This working aspect of alias this + opDispatch will break after your changes (though I'm not sure if this is a huge problem). The reason to have opDispatch override alias this is because of the level of control in what to override. alias this does not allow fine grained overriding of certain pieces, it's all or nothing. In other words, with alias this having precedence, opDispatch becomes neutered. With opDispatch having precedence, one can select the pieces to allow to trickle through to alias this. To me, because opDispatch is implemented in the most derived type, and because you can limit its effect, it should have total precedence over everything except other defined members in that derived type. It's a question of who is in charge of this derived type's API. opDispatch is a way to avoid boilerplating a ton of stuff. But the result of opDispatch should be considered first-class members. And let us not kid ourselves. If we define an ordering for precedence here, it is not going to be changed in the future. Broken code will preclude that possibility. "Loosening the screws" does not mean "change the complete ordering of the feature." -Steve
Apr 02 2015
prev sibling next sibling parent "Jeff Jones" <Jeff Jones.com> writes:
On Sunday, 29 March 2015 at 17:34:21 UTC, IgorStepanov wrote:
 3. is(T: B) should raise an error if there are many ways to 
 convert T to B.
I think this will cause future problems. How hard would it be to include at type algebra system? (being able to use &, |, etc on types... sort of Venn diagram'ish. Also, is(T:B) should reflect what it means. Just because a dog can be classed many ways doesn't mean it's not a dog. I realize that this makes things harder but is(T:B) raising an error if there are more than one conversion path just seems wrong. isonly(T:B) or whatever makes visual sense would be a better option IMO.
Mar 31 2015
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 03/29/2015 07:34 PM, IgorStepanov wrote:
 3. is(T: B) should raise an error if there are many ways to convert T to B.
This is inconsistent with how 'is' works otherwise, and it breaks template constraints in annoying ways. (There is no SFINAE.) auto foo()()if(true){ return 1; } // this is the one you want auto foo()()if(a){ return 2; } // this is the one with is(T: B) void main(){ foo(); // error } Is the intention that no types with multiple alias this paths to some type should be defined in the first place?
May 25 2015
parent reply "IgorStepanov" <wazar mail.ru> writes:
On Monday, 25 May 2015 at 22:32:55 UTC, Timon Gehr wrote:
 On 03/29/2015 07:34 PM, IgorStepanov wrote:
 3. is(T: B) should raise an error if there are many ways to 
 convert T to B.
This is inconsistent with how 'is' works otherwise, and it breaks template constraints in annoying ways. (There is no SFINAE.) auto foo()()if(true){ return 1; } // this is the one you want auto foo()()if(a){ return 2; } // this is the one with is(T: B) void main(){ foo(); // error } Is the intention that no types with multiple alias this paths to some type should be defined in the first place?
This problem was discussed early, and Andrey sad that is(D: B) should raise a error, if D can be converted to B via multiple ways. I mostly agree with Andrey. The my main argument: wrong convertion shouldn't be implicitly hidden and I suggested return true even if there are many ways to convertion. My example: auto foo(T)(){ return 1; } auto foo(T)()if(is(T: int)){ return 2; } struct Foo { //... } struct Bar { Foo f; int i; alias i this; } auto ret = foo!Bar; assert(ret == 2); //exactly the second function After that, imagine, someone added alias intVal this to Foo. Now there are many ways to convert Bar to int. However, user don't know about it. And if foo!Bar will start to return 1, it is very ugly situation.
May 25 2015
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 05/26/2015 01:17 AM, IgorStepanov wrote:
 My example:
 auto foo(T)(){ return 1; }
 auto foo(T)()if(is(T: int)){ return 2; }

 struct Foo
 {
      //...
 }
 struct Bar
 {
       Foo f;
       int i;
       alias i this;
 }

 auto ret = foo!Bar;
 assert(ret == 2); //exactly the second function
 ...
(No, this actually raises an ambiguity error, but I see the point.)
 After that, imagine, someone added alias intVal this to Foo.
 Now there are many ways to convert Bar to int. However, user
 don't know about it.

 And if foo!Bar will start to return 1, it is very ugly situation.
I'm not convinced the alternative is better. One can still do e.g.: auto foo(T)()if(!is(typeof({static assert(is(T: int));}))){ return 1; } auto foo(T)()if(is(typeof({static assert(is(T: int));}))){ return 2; }
May 25 2015
parent "IgorStepanov" <wazar mail.ru> writes:
On Monday, 25 May 2015 at 23:36:00 UTC, Timon Gehr wrote:
 On 05/26/2015 01:17 AM, IgorStepanov wrote:
 My example:
 auto foo(T)(){ return 1; }
 auto foo(T)()if(is(T: int)){ return 2; }

 struct Foo
 {
     //...
 }
 struct Bar
 {
      Foo f;
      int i;
      alias i this;
 }

 auto ret = foo!Bar;
 assert(ret == 2); //exactly the second function
 ...
(No, this actually raises an ambiguity error, but I see the point.)
 After that, imagine, someone added alias intVal this to Foo.
 Now there are many ways to convert Bar to int. However, user
 don't know about it.

 And if foo!Bar will start to return 1, it is very ugly 
 situation.
I'm not convinced the alternative is better. One can still do e.g.: auto foo(T)()if(!is(typeof({static assert(is(T: int));}))){ return 1; } auto foo(T)()if(is(typeof({static assert(is(T: int));}))){ return 2; }
Yes, we will able hack the situation: for example via __traits(compile, ...) or via is(typeof(...)) However all those hacks are known and in strange template behaviour we able to find all those places. I think, error is not bad. Multiple alias this is a new feature, and this solution allows us to catch all error and safely try this feature. Later we will able to relax all rules, when we will sure that it is safe.
May 25 2015