www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Automatic return type covariance for functions that return this?

reply Ben Davis <entheh cantab.net> writes:
Hi,

Is it possible in D to achieve this effect:

class Super {
   typeof(this) doStuff() { ...; return this; }
}

class Sub : Super {
   //doStuff is NOT explicitly overridden here
}

Sub x = (new Sub()).doStuff();

The last line doesn't compile because doStuff() returns Super. Is there 
a way to make it return Sub without having to explicitly override the 
function?

Thanks in advance,

Ben :)
Sep 15 2012
next sibling parent reply Ben Davis <entheh cantab.net> writes:
Never mind, I found the answer in the 'templates' page of the spec:

class Super {
    T doStuff(this T)() { ...; return cast(T)this; }
}

Sub x = (new Sub()).doStuff();

It seems a bit of a shame that I need the cast, but it's a small thing :)

On 15/09/2012 22:53, Ben Davis wrote:
 Hi,

 Is it possible in D to achieve this effect:

 class Super {
    typeof(this) doStuff() { ...; return this; }
 }

 class Sub : Super {
    //doStuff is NOT explicitly overridden here
 }

 Sub x = (new Sub()).doStuff();

 The last line doesn't compile because doStuff() returns Super. Is there
 a way to make it return Sub without having to explicitly override the
 function?

 Thanks in advance,

 Ben :)

Sep 15 2012
parent "bearophile" <bearophileHUGS lycos.com> writes:
Andrej Mitrovic:

 I saw this
 static cast thingy laying around somewhere:

 auto static_cast(T,U)(U source)
 {
     return cast(T)(cast(void*)source);
 }

Maybe you meant: http://d.puremagic.com/issues/show_bug.cgi?id=5559 Bye, bearophile
Sep 15 2012
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 9/15/12, Ben Davis <entheh cantab.net> wrote:
 The last line doesn't compile because doStuff() returns Super. Is there
 a way to make it return Sub without having to explicitly override the
 function?

You need a dynamic cast at the call site: Sub x = cast(Sub)(new Sub()).doStuff(); x will be null if doStuff doesn't actually return a Sub object (replace 'new Sub' with 'new Super' for demonstration). You can't guarantee that the 'this' reference returned in the base class doStuff method will be of dynamic type 'Sub', that's why implicit conversions don't work. Either define this method in every subclass or use casts at the call site. Maybe you're looking for automatic injection of code into every subclass, but I don't think this is possible in D. Using mixins might work, but you'd still have to instantiate a mixin in every subclass by hand.
Sep 15 2012
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 9/15/12, Ben Davis <entheh cantab.net> wrote:
 Never mind, I found the answer in the 'templates' page of the spec:

 class Super {
     T doStuff(this T)() { ...; return cast(T)this; }
 }

 Sub x = (new Sub()).doStuff();

 It seems a bit of a shame that I need the cast, but it's a small thing :)

Ah the template this solution, I always forget about that little trick! Nicely done. :)
Sep 15 2012
prev sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 9/15/12, Ben Davis <entheh cantab.net> wrote:
 Never mind, I found the answer in the 'templates' page of the spec:

 class Super {
     T doStuff(this T)() { ...; return cast(T)this; }
 }

Btw I think that's a dynamic cast, unless the compiler can optimize it (I mean it should since it's a template function right?). I saw this static cast thingy laying around somewhere: auto static_cast(T,U)(U source) { return cast(T)(cast(void*)source); }
Sep 15 2012