Forwarding or merging 'this' into a child class to aid chaining methods?

Steven Schveighoffer schveiguy at yahoo.com
Thu Mar 6 11:36:19 PST 2014


On Thu, 06 Mar 2014 14:04:48 -0500, Gary Willoughby <dev at 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


More information about the Digitalmars-d-learn mailing list