Thread overview
Q: How to return sub class from base class method
Jun 18, 2007
Myron Alexander
Jun 18, 2007
Myron Alexander
Jun 18, 2007
Kirk McDonald
Jun 18, 2007
Myron Alexander
June 18, 2007
Hello.

I have a class structure as such:

> class A {
>    typeof(this) doSomething (????) {
>       ...
>       return this;
>    }
> }
> 
> class B : A {
>    typeof(this) doSomethingElse (????) {
>       ...
>       return this;
>    }
> }
> 
> void main () {
>    // Fails
>    B b = (new B()).doSomething (???).doSomethingElse (???);
> }

The method chain fails as doSomething returns type A.

I want to define method doSomething in such a way that it will return the specialized type (B) rather than the base type.

I'm currently using a mixin to mixin overriding code:

> template doSomethingOverride () {
>    override typeof(this) doSomething (????) {
>       super.doSomething (????);
>       return this;
>    }
> }

Is there a way to set the return type as the type instantiated?

Thanks,

Myron.
June 18, 2007
Myron Alexander wrote:

> I have a class structure as such:
> 
>> class A {
>>    typeof(this) doSomething (????) {
>>       ...
>>       return this;
>>    }
>> }
>> 
>> class B : A {
>>    typeof(this) doSomethingElse (????) {
>>       ...
>>       return this;
>>    }
>> }
>> 
>> void main () {
>>    // Fails
>>    B b = (new B()).doSomething (???).doSomethingElse (???);
>> }
> 
> The method chain fails as doSomething returns type A.
> 
> I want to define method doSomething in such a way that it will return the specialized type (B) rather than the base type.
> 
> Is there a way to set the return type as the type instantiated?

Yes, you can use CRTP
(http://en.wikipedia.org/wiki/Curiously_Recurring_Template_Pattern).

class A(T) {
  T doSomething() {
    ...
    return cast(T)this;
  }
}

class B(T) : A!(T) {
  T doSomethingElse() {
    ...
    return cast(T)this;
  }
}

There might be other (more clever) ways to do this too. Like a mixin for
the "selftype" or something.
June 18, 2007
Jari-Matti Mäkelä wrote:
> 
> Yes, you can use CRTP
> (http://en.wikipedia.org/wiki/Curiously_Recurring_Template_Pattern).
> 
> class A(T) {
>   T doSomething() {
>     ...
>     return cast(T)this;
>   }
> }
> 
> class B(T) : A!(T) {
>   T doSomethingElse() {
>     ...
>     return cast(T)this;
>   }
> }
> 
> There might be other (more clever) ways to do this too. Like a mixin for
> the "selftype" or something.

Thanks for the suggestion. I am hoping for a solution that does not require me to set a type on instantiation. I just want to write:

B b = (new B()).doSomething (???).doSomethingElse (???);

If the language does not have a way to do it, that's ok, the mixin solution works.

Regards,

Myron.
June 18, 2007
Jari-Matti Mäkelä wrote:
> Myron Alexander wrote:
> 
> 
>>I have a class structure as such:
>>
>>
>>>class A {
>>>   typeof(this) doSomething (????) {
>>>      ...
>>>      return this;
>>>   }
>>>}
>>>
>>>class B : A {
>>>   typeof(this) doSomethingElse (????) {
>>>      ...
>>>      return this;
>>>   }
>>>}
>>>
>>>void main () {
>>>   // Fails
>>>   B b = (new B()).doSomething (???).doSomethingElse (???);
>>>}
>>
>>The method chain fails as doSomething returns type A.
>>
>>I want to define method doSomething in such a way that it will return
>>the specialized type (B) rather than the base type.
>>
>>Is there a way to set the return type as the type instantiated?
> 
> 
> Yes, you can use CRTP
> (http://en.wikipedia.org/wiki/Curiously_Recurring_Template_Pattern).
> 
> class A(T) {
>   T doSomething() {
>     ...
>     return cast(T)this;
>   }
> }
> 
> class B(T) : A!(T) {
>   T doSomethingElse() {
>     ...
>     return cast(T)this;
>   }
> }
> 
> There might be other (more clever) ways to do this too. Like a mixin for
> the "selftype" or something.

I believe B should look like this, if you're using that pattern:

class B : A!(B) {
  B doSomethingElse() {
    // ...
    return this;
  }
}

Thus, B is derived from a class template to which you pass B as a parameter. This is often used in C++ as a way of emulating mixin-like behavior. Thus, D's template mixins could very well be a better solution.

-- 
Kirk McDonald
http://kirkmcdonald.blogspot.com
Pyd: Connecting D and Python
http://pyd.dsource.org
June 18, 2007
Kirk McDonald wrote:

> Jari-Matti Mäkelä wrote:
>> class A(T) {
>>   T doSomething() {
>>     ...
>>     return cast(T)this;
>>   }
>> }
>> 
>> class B(T) : A!(T) {
>>   T doSomethingElse() {
>>     ...
>>     return cast(T)this;
>>   }
>> }
>> 
>> There might be other (more clever) ways to do this too. Like a mixin for
>> the "selftype" or something.
> 
> I believe B should look like this, if you're using that pattern:
> 
> class B : A!(B) {
>    B doSomethingElse() {
>      // ...
>      return this;
>    }
> }

Actually no - class B was supposed to be in the middle of the hierarchy so class C would have looked like that :)

Something like

class A(T = A) { ... }
class B(T = B) : A!(T) { ... }

would have been nice for those non-abstract base classes so they could have been instantiated too, but apparently the compiler didn't want to co-operate this time.

> 
> Thus, B is derived from a class template to which you pass B as a parameter. This is often used in C++ as a way of emulating mixin-like behavior. Thus, D's template mixins could very well be a better solution.
> 

Feel free to create a better solution :)
June 18, 2007
Jari-Matti Mäkelä wrote:
> Kirk McDonald wrote:
> 
>> Jari-Matti Mäkelä wrote:
>>> class A(T) {
>>>   T doSomething() {
>>>     ...
>>>     return cast(T)this;
>>>   }
>>> }
>>>
>>> class B(T) : A!(T) {
>>>   T doSomethingElse() {
>>>     ...
>>>     return cast(T)this;
>>>   }
>>> }
>>>
>>> There might be other (more clever) ways to do this too. Like a mixin for
>>> the "selftype" or something.
>> I believe B should look like this, if you're using that pattern:
>>
>> class B : A!(B) {
>>    B doSomethingElse() {
>>      // ...
>>      return this;
>>    }
>> }
> 
> Actually no - class B was supposed to be in the middle of the hierarchy so class C would have looked like that :)
> 
> Something like
> 
> class A(T = A) { ... }
> class B(T = B) : A!(T) { ... }
> 
> would have been nice for those non-abstract base classes so they could have been instantiated too, but apparently the compiler didn't want to co-operate this time.
> 
>> Thus, B is derived from a class template to which you pass B as a parameter. This is often used in C++ as a way of emulating mixin-like behavior. Thus, D's template mixins could very well be a better solution.
>>
> 
> Feel free to create a better solution :)

Thanks all.

I am happy with the mixin solution, even if I forget to add the mixin, the compiler will generate an error when I try to chain the class methods after the doSomething so it's not a dangerous one at that.

Just for your information, I attached the test source where I am using it. The doSomething method here is called 'initCause'.

Regards,

Myron.