digitalmars.D.learn - Forwarding or merging 'this' into a child class to aid chaining
- Gary Willoughby (31/31) Mar 06 2014 I'm trying to create methods across class hierarchies that can be
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (39/69) Mar 06 2014 I had the exact problem in C++ which I have solved with the help of
- anonymous (6/37) Mar 06 2014 public auto foo(this T)()
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (7/12) Mar 06 2014 Sweet! :) Unfortunately, it has a somewhat obfuscated definition:
- anonymous (6/10) Mar 06 2014 [...]
- Gary Willoughby (2/7) Mar 06 2014 Nice! This seems to be what i was after and it works well.
- Steven Schveighoffer (24/54) Mar 06 2014 There are two possibilities.
I'm trying to create methods across class hierarchies that can be chained nicely but i'm running into the problem that 'this' declared in a parent class only refers to that type. Is there a way i can get the following code to perform in the way i expect? import std.stdio; class Foo { public auto foo() { return this; } } class Bar : Foo { public auto bar() { return this; } } void main(string[] args) { Bar bar = new Bar().bar().foo(); } test2.d(21): Error: cannot implicitly convert expression ((new Bar).bar().foo()) of type test2.Foo to test2.Bar Failed: 'dmd' '-v' '-o-' 'test2.d' '-I.' How can i make the above marked 'this' refer to Bar when being called in a chain? When i call the methods like this each method call seems to implicitly convert 'this' into that method's containing class' instance, breaking the code and sometimes hiding child methods.
Mar 06 2014
On 03/06/2014 11:04 AM, Gary Willoughby wrote:I'm trying to create methods across class hierarchies that can be chained nicely but i'm running into the problem that 'this' declared in a parent class only refers to that type. Is there a way i can get the following code to perform in the way i expect? import std.stdio; class Foo { public auto foo() { return this; } } class Bar : Foo { public auto bar() { return this; } } void main(string[] args) { Bar bar = new Bar().bar().foo(); } test2.d(21): Error: cannot implicitly convert expression ((new Bar).bar().foo()) of type test2.Foo to test2.Bar Failed: 'dmd' '-v' '-o-' 'test2.d' '-I.' How can i make the above marked 'this' refer to Bar when being called in a chain? When i call the methods like this each method call seems to implicitly convert 'this' into that method's containing class' instance, breaking the code and sometimes hiding child methods.I had the exact problem in C++ which I have solved with the help of boost::shared_ptr, boost::enable_shared_from_this, and by passing down the most derived pointer type as a template parameter: template <class MostDerived> class FooImpl : public FooInterface, public boost::enable_shared_from_this<MostDerived> { // ... protected: typedef boost::shared_ptr<MostDerived> MostDerivedPtr; MostDerivedPtr foo()(); // <-- HERE, the return type is // the most derived type }; Let's try something similar for D: import std.stdio; interface Foo { // ... needed if there is non-specific interface ... } class FooImpl(MostDerived) : Foo { public MostDerived foo() { return cast(MostDerived)this; } } class Bar : FooImpl!Bar { public Bar bar() { return this; } } void main(string[] args) { Bar bar = new Bar().bar().foo(); } Ali
Mar 06 2014
On Thursday, 6 March 2014 at 19:04:50 UTC, Gary Willoughby wrote:I'm trying to create methods across class hierarchies that can be chained nicely but i'm running into the problem that 'this' declared in a parent class only refers to that type. Is there a way i can get the following code to perform in the way i expect? import std.stdio; class Foo { public auto foo() { return this; } } class Bar : Foo { public auto bar() { return this; } } void main(string[] args) { Bar bar = new Bar().bar().foo(); } test2.d(21): Error: cannot implicitly convert expression ((new Bar).bar().foo()) of type test2.Foo to test2.Bar Failed: 'dmd' '-v' '-o-' 'test2.d' '-I.' How can i make the above marked 'this' refer to Bar when being called in a chain? When i call the methods like this each method call seems to implicitly convert 'this' into that method's containing class' instance, breaking the code and sometimes hiding child methods.public auto foo(this T)() { return cast(T) this; } http://dlang.org/template.html#TemplateThisParameter
Mar 06 2014
On 03/06/2014 11:16 AM, anonymous wrote:public auto foo(this T)() { return cast(T) this; } http://dlang.org/template.html#TemplateThisParameterSweet! :) Unfortunately, it has a somewhat obfuscated definition: "TemplateThisParameters are used in member function templates to pick up the type of the this reference." "type of the this reference" does not explain that it is about the type of the most derived object. Ali
Mar 06 2014
On Thursday, 6 March 2014 at 19:30:25 UTC, Ali Çehreli wrote:On 03/06/2014 11:16 AM, anonymous wrote:[...][...]http://dlang.org/template.html#TemplateThisParameter"type of the this reference" does not explain that it is about the type of the most derived object.Well, it isn't. It works with new Bar().bar().foo(), because new Bar().bar() is a Bar. This wouldn't work: Foo foo = new Bar().bar(); Bar bar = foo.foo();
Mar 06 2014
On Thursday, 6 March 2014 at 19:16:07 UTC, anonymous wrote:public auto foo(this T)() { return cast(T) this; } http://dlang.org/template.html#TemplateThisParameterNice! This seems to be what i was after and it works well.
Mar 06 2014
On Thu, 06 Mar 2014 14:04:48 -0500, Gary Willoughby <dev nomad.so> wrote:I'm trying to create methods across class hierarchies that can be chained nicely but i'm running into the problem that 'this' declared in a parent class only refers to that type. Is there a way i can get the following code to perform in the way i expect? import std.stdio; class Foo { public auto foo() { return this; } } class Bar : Foo { public auto bar() { return this; } } void main(string[] args) { Bar bar = new Bar().bar().foo(); } test2.d(21): Error: cannot implicitly convert expression ((new Bar).bar().foo()) of type test2.Foo to test2.Bar Failed: 'dmd' '-v' '-o-' 'test2.d' '-I.' How can i make the above marked 'this' refer to Bar when being called in a chain? When i call the methods like this each method call seems to implicitly convert 'this' into that method's containing class' instance, breaking the code and sometimes hiding child methods.There are two possibilities. First, you can create a non-virtual function, which can be templated on the type called with: T foo(this T)() // T == whatever type you called the method as. { return cast(T)this; // the cast is necessary because inside foo, 'this' is base class type } Second, you can override the function in subsequent classes: class Bar : Foo { public auto foo() { return this;} } And of course, if you just want to inherit the implementation: public auto foo() { return cast(Foo)super.foo();} This gets tricky if you are not certain of the base implementation. If it could ever return a "Foo" that is not actually 'this', then the function will likely not work correctly. I had proposed, a long time ago, a mechanism to note that a function should always return 'this', and the compiler could take that into account (enforce it, and make assumptions based on the type called with). The response I got was to use the template form. -Steve
Mar 06 2014