digitalmars.D.learn - template this and traits getOverloads issue.
- BBasile (46/49) Nov 20 2015 Background:
- Alex Parrill (44/93) Nov 20 2015 Templates are not virtual, which is why you might be running into
- BBasile (7/9) Nov 20 2015 On Friday, 20 November 2015 at 14:18:00 UTC, Alex Parrill wrote:
- Alex Parrill (37/37) Nov 20 2015 Alternatively, you can use a static method and pass in the
- BBasile (17/22) Nov 20 2015 Initially this solution looked awesome but when `bug()` is
- Adam D. Ruppe (23/25) Nov 20 2015 Indeed, this is a good answer too.
- BBasile (9/35) Nov 20 2015 I review what I said before. Actually it doesn't work that well.
- Adam D. Ruppe (39/45) Nov 20 2015 Did you try using a template this parameter like I said in my
- BBasile (13/27) Nov 20 2015 Yes, using an index and a second call to getOverloads works,
- Adam D. Ruppe (4/6) Nov 20 2015 auto this_ = cast(T) this;
Background: =========== http://stackoverflow.com/questions/33764540/warning-about-overriden-methods-when-using-a-mixin Why this horrible trick has to be used: ======================================= cast this as (T) in a function template that's been mixed in an ancestor is not always usable, unless I miss something: ---- import std.stdio; mixin template Bug() { import std.traits; void bug(T)() { foreach(member; __traits(allMembers, T)) foreach(overload; __traits(getOverloads, T, member)) { auto dg = &overload; writeln(member); } } } class A { mixin Bug; this(){bug!A;} void foo(){} } class B: A { void bar(){} void bar(uint a){} this(){bug!B;} } void main(){ new A; new B; } ----a.d(11,27): Error: this for bar needs to be type B not type a.A a.d(11,27): Error: this for bar needs to be type B not type a.A a.d(11,27): Error: this for this needs to be type B not type a.Aeverything that can be done to avoid the compilations errors will also prevent "bar" to be written in the output (because a B will never be analyzed). The "only" fix I see is like in the stack overflow answer: statically check if the mixin methods are already there and remix the mixin in each descendant, so that the getOverloads traits works on the right 'this'. What do you think ? is it a bug ?
Nov 20 2015
On Friday, 20 November 2015 at 14:01:13 UTC, BBasile wrote:Background: =========== http://stackoverflow.com/questions/33764540/warning-about-overriden-methods-when-using-a-mixin Why this horrible trick has to be used: ======================================= cast this as (T) in a function template that's been mixed in an ancestor is not always usable, unless I miss something: ---- import std.stdio; mixin template Bug() { import std.traits; void bug(T)() { foreach(member; __traits(allMembers, T)) foreach(overload; __traits(getOverloads, T, member)) { auto dg = &overload; writeln(member); } } } class A { mixin Bug; this(){bug!A;} void foo(){} } class B: A { void bar(){} void bar(uint a){} this(){bug!B;} } void main(){ new A; new B; } ----Templates are not virtual, which is why you might be running into issues here; bug thinks it's being called on an `A` object. But you don't need a template for this case; mixin templates have access to `this`: --- import std.stdio; mixin template Bug() { import std.traits; override void bug() { foreach(member; __traits(allMembers, typeof(this))) foreach(overload; __traits(getOverloads, typeof(this), member)) { auto dg = &overload; writeln(member); } } } // Interface to allow for mixin template to use `override` without worrying if // `bug` is the first implementation or not. interface IF { void bug(); } class A : IF { mixin Bug; this(){bug();} void foo(){} } class B: A { mixin Bug; // need mixin on B now to override `bug` for the new class void bar(){} void bar(uint a){} } void main(){ new A; new B; }a.d(11,27): Error: this for bar needs to be type B not type a.A a.d(11,27): Error: this for bar needs to be type B not type a.A a.d(11,27): Error: this for this needs to be type B not type a.Aeverything that can be done to avoid the compilations errors will also prevent "bar" to be written in the output (because a B will never be analyzed). The "only" fix I see is like in the stack overflow answer: statically check if the mixin methods are already there and remix the mixin in each descendant, so that the getOverloads traits works on the right 'this'. What do you think ? is it a bug ?
Nov 20 2015
On Friday, 20 November 2015 at 14:18:00 UTC, Alex Parrill wrote: If the mixin has to be used on class and on struct, I cant use an interface. In this case override will create an error and go back to the solution on SO: statically check if things are already there.Templates are not virtual, which is why you might be running into issues here; bug thinks it's being called on an `A` object.This is the origin of the problem, I totally forgot this limitation.
Nov 20 2015
Alternatively, you can use a static method and pass in the instance. Note that `new B` will print A's members twice, because A's constructor is always called and `__traits(allMembers, B)` includes A's members. --- import std.stdio; mixin template Bug() { import std.traits; static void bug(T)(T t) { writeln(">", T.stringof); foreach(member; __traits(allMembers, T)) foreach(overload; __traits(getOverloads, T, member)) { auto dg = &overload; writeln(member); } } } class A { mixin Bug; this(){bug!A(this);} void foo(){} } class B: A { this(){bug!B(this);} void bar(){} void bar(uint a){} } void main(){ new A; new B; }
Nov 20 2015
On Friday, 20 November 2015 at 14:39:29 UTC, Alex Parrill wrote:Alternatively, you can use a static method and pass in the instance.Initially this solution looked awesome but when `bug()` is static, `&dg` returns some functions, not some delegates, which is a problem: this implies that I have to find the matching delegate type, set `.funcptr` to the value of the `dg` function, set `.ptr` to the value of 't'...well not so hard I guess. But then I have no way to detect when a function is really a function or something that might be delegate when instantiated: { auto dg = &overload; if (member == "bar") writeln(member, " ", typeof(dg).stringof); } --> bar void function() --> bar void function(uint a)Note that `new B` will print A's members twice, because A's constructor is always called and `__traits(allMembers, B)` includes A's members.Not a problem, it was already the case anyway. But thx much for the attempt.
Nov 20 2015
On Friday, 20 November 2015 at 14:18:00 UTC, Alex Parrill wrote:But you don't need a template for this case; mixin templates have access to `this`:Indeed, this is a good answer too. The difference between this and the template thing I did is that yours is virtual so calling it through an interface will work even on subclasses. However, you must mix it into each sub class. Mine is a template that only needs to be in the base class/interface, but also need a `this` of the derived type to see the derived type. (That's why I ran `this.bug();` in the constructor of B btw) If you call it on an variable typed as the interface, it will only show interface members. IF i = new A(); i.bug(); // would only show interface members with mine A a = new A(); a.bug(); // will now show A's members too That's what the template this parameter does: the type of this at the *usage site* is passed as the parameter. With your solution, the type of this at the *mixin site* is available. I think your solution is generally better for stuff like serialization where you are passed an interface but need child members too. The template this param I used is nice for interface functions that need some kind of covariance; returning a type based on how it was used.
Nov 20 2015
On Friday, 20 November 2015 at 15:03:06 UTC, Adam D. Ruppe wrote:On Friday, 20 November 2015 at 14:18:00 UTC, Alex Parrill wrote:I review what I said before. Actually it doesn't work that well. Using the two methods (yours or A.Parrill's one) the protected members in a class that's located in another module are not accessible, the relationship to the current class the traits code is ran into is totally lost and only public members are visible. when bug() delcaration is `static void bug(T)(T t)`, pointer to members are get using __traits(getMember, t, member) and in your solution using _this instead of t. So it's a more for a less.But you don't need a template for this case; mixin templates have access to `this`:Indeed, this is a good answer too. The difference between this and the template thing I did is that yours is virtual so calling it through an interface will work even on subclasses. However, you must mix it into each sub class. Mine is a template that only needs to be in the base class/interface, but also need a `this` of the derived type to see the derived type. (That's why I ran `this.bug();` in the constructor of B btw) If you call it on an variable typed as the interface, it will only show interface members. IF i = new A(); i.bug(); // would only show interface members with mine A a = new A(); a.bug(); // will now show A's members too That's what the template this parameter does: the type of this at the *usage site* is passed as the parameter. With your solution, the type of this at the *mixin site* is available. I think your solution is generally better for stuff like serialization where you are passed an interface but need child members too. The template this param I used is nice for interface functions that need some kind of covariance; returning a type based on how it was used.
Nov 20 2015
On Friday, 20 November 2015 at 14:01:13 UTC, BBasile wrote:everything that can be done to avoid the compilations errors will also prevent "bar" to be written in the output (because a B will never be analyzed). The "only" fix I see is like in the stack overflow answer: statically check if the mixin methods are already there and remix the mixin in each descendant, so that the getOverloads traits works on the right 'this'.Did you try using a template this parameter like I said in my comment? import std.stdio; mixin template Bug() { import std.traits; void bug(this T)() { T this_ = cast(T) this; foreach(member; __traits(allMembers, T)) foreach(idx, overload; __traits(getOverloads, T, member)) { auto dg = &(__traits(getOverloads, this_, member)[idx]); writeln(T.stringof, ".", member, " ", typeof(dg).stringof); } } } class A { mixin Bug; this(){bug;} void foo(){} } class B: A { void bar(){} void bar(uint a){} this(){this.bug;} } void main(){ new A; new B; } There's a couple quirks in there, but I think you'll find the output shows what you want to see.
Nov 20 2015
On Friday, 20 November 2015 at 14:49:28 UTC, Adam D. Ruppe wrote:On Friday, 20 November 2015 at 14:01:13 UTC, BBasile wrote:Yes, using an index and a second call to getOverloads works, "finally". No need to remix. Thx. I hadn't understood what you meant on SO. One last question: is it possible to nest the calls to functions that take this kind of parameters ? mixin template Bug() { void bug0(this T)(){} void bug1(this T)(){} void allbugs(this T)(){this.bug0(); this.bug1();} } I've tried different parameters and templates and it never works.everything that can be done to avoid the compilations errors will also prevent "bar" to be written in the output (because a B will never be analyzed). The "only" fix I see is like in the stack overflow answer: statically check if the mixin methods are already there and remix the mixin in each descendant, so that the getOverloads traits works on the right 'this'.Did you try using a template this parameter like I said in my comment? foreach(idx, overload; __traits(getOverloads, T, member)) { auto dg = &(__traits(getOverloads, this_, member)[idx]);
Nov 20 2015
On Friday, 20 November 2015 at 15:43:00 UTC, BBasile wrote:One last question: is it possible to nest the calls to functions that take this kind of parameters ?auto this_ = cast(T) this; this_.bug0(); this_.bug1();
Nov 20 2015