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

Ali Çehreli acehreli at yahoo.com
Thu Mar 6 11:15:29 PST 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



More information about the Digitalmars-d-learn mailing list