www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Covariant return type

reply Aarti_pl <aarti interia.pl> writes:
Hello!

Shouldn't code below work?:

//-------------------------------------------

abstract class Storage {
     Storage get() {
         return this;
     }
}

class SpecificStorage : Storage {
     void print() {}
}

void main() {
     SpecificStorage s = (new SpecificStorage).get();
     s.print;
}

//-------------------------------------------

Unfortunately currently you have to add overridden implementation of 
get() in SpecificStorage, like below (what is a little bit tedious work):

     SpecificStorage get() {
         return this;
     }


But my intuition about that would be that "this" pointer from method get 
from Storage class will point to "SpecificStorage" when there is 
instantiated SpecificStorage. But it looks that in fact this points to 
"Storage".

I don't know if it is bug or enhancement or even if it has any sense :-).

Please answer what you think...

BR
Marcin Kuszczak
(aarti_pl)
Mar 22 2007
parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Aarti_pl" <aarti interia.pl> wrote in message 
news:ettjqu$14jb$1 digitalmars.com...
 Hello!

 Shouldn't code below work?:

 //-------------------------------------------

 abstract class Storage {
     Storage get() {
         return this;
     }
 }

 class SpecificStorage : Storage {
     void print() {}
 }

 void main() {
     SpecificStorage s = (new SpecificStorage).get();
     s.print;
 }

 //-------------------------------------------

 Unfortunately currently you have to add overridden implementation of get() 
 in SpecificStorage, like below (what is a little bit tedious work):

     SpecificStorage get() {
         return this;
     }


 But my intuition about that would be that "this" pointer from method get 
 from Storage class will point to "SpecificStorage" when there is 
 instantiated SpecificStorage. But it looks that in fact this points to 
 "Storage".

Sounds like it's behaving correctly to me. When you call .get on a SpecificStorage, the only override of it is the one that returns a Storage in the base class, and you can't cast from Storage to SpecificStorage implicitly. The language will not implicitly define covariantly returning versions of your methods for you; that's up to you.
Mar 22 2007
parent reply Aarti_pl <aarti interia.pl> writes:
Jarrett Billingsley napisał(a):
 "Aarti_pl" <aarti interia.pl> wrote in message 
 news:ettjqu$14jb$1 digitalmars.com...
 Hello!

 Shouldn't code below work?:

 //-------------------------------------------

 abstract class Storage {
     Storage get() {
         return this;
     }
 }

 class SpecificStorage : Storage {
     void print() {}
 }

 void main() {
     SpecificStorage s = (new SpecificStorage).get();
     s.print;
 }

 //-------------------------------------------

 Unfortunately currently you have to add overridden implementation of get() 
 in SpecificStorage, like below (what is a little bit tedious work):

     SpecificStorage get() {
         return this;
     }


 But my intuition about that would be that "this" pointer from method get 
 from Storage class will point to "SpecificStorage" when there is 
 instantiated SpecificStorage. But it looks that in fact this points to 
 "Storage".

Sounds like it's behaving correctly to me. When you call .get on a SpecificStorage, the only override of it is the one that returns a Storage in the base class, and you can't cast from Storage to SpecificStorage implicitly. The language will not implicitly define covariantly returning versions of your methods for you; that's up to you.

Yes, but in fact I don't want to loose type information and upcast to Storage. I just want to return 'this' as it is when return is invoked. Such a behavior seems a little bit nonsense when there is covariance return type feature in programming language. To get covariance I have many time reimplement same code in every inherited class just to trigger proper behaviour. I think that it should not break anything when instead of making upcasting during return compiler just return concreate type and probably later make upcast when e.g. assigning to Storage variable. It should also not break visibility as I return SpecificStorage - If I would want to return Storage I can make upcast before return even in base class: Storage get() { return cast(Storage)this; } .... But maybe I am wrong... Do you think it would be enhancement for language to have something like this? Or it can break something?... I get to this problem with few simple, guarded setters methods in base class, which should return 'this' to achieve chaining. They should behave exactly same in all derived classes and currently the only way is to copy slightly modified implementation to derived classes... If you think it could be useful I will fill enhancement on bugzilla... Or maybe it should be putted for discussion to main D forum? (as it doesn't look like error according to answer)... BR Marcin Kuszczak (aarti_pl)
Mar 22 2007
next sibling parent Chris Nicholson-Sauls <ibisbasenji gmail.com> writes:
Aarti_pl wrote:
 
 
 Jarrett Billingsley napisał(a):
 "Aarti_pl" <aarti interia.pl> wrote in message 
 news:ettjqu$14jb$1 digitalmars.com...
 Hello!

 Shouldn't code below work?:

 //-------------------------------------------

 abstract class Storage {
     Storage get() {
         return this;
     }
 }

 class SpecificStorage : Storage {
     void print() {}
 }

 void main() {
     SpecificStorage s = (new SpecificStorage).get();
     s.print;
 }

 //-------------------------------------------

 Unfortunately currently you have to add overridden implementation of 
 get() in SpecificStorage, like below (what is a little bit tedious 
 work):

     SpecificStorage get() {
         return this;
     }


 But my intuition about that would be that "this" pointer from method 
 get from Storage class will point to "SpecificStorage" when there is 
 instantiated SpecificStorage. But it looks that in fact this points 
 to "Storage".

Sounds like it's behaving correctly to me. When you call .get on a SpecificStorage, the only override of it is the one that returns a Storage in the base class, and you can't cast from Storage to SpecificStorage implicitly. The language will not implicitly define covariantly returning versions of your methods for you; that's up to you.

Yes, but in fact I don't want to loose type information and upcast to Storage. I just want to return 'this' as it is when return is invoked. Such a behavior seems a little bit nonsense when there is covariance return type feature in programming language. To get covariance I have many time reimplement same code in every inherited class just to trigger proper behaviour. I think that it should not break anything when instead of making upcasting during return compiler just return concreate type and probably later make upcast when e.g. assigning to Storage variable. It should also not break visibility as I return SpecificStorage - If I would want to return Storage I can make upcast before return even in base class: Storage get() { return cast(Storage)this; } .... But maybe I am wrong... Do you think it would be enhancement for language to have something like this? Or it can break something?... I get to this problem with few simple, guarded setters methods in base class, which should return 'this' to achieve chaining. They should behave exactly same in all derived classes and currently the only way is to copy slightly modified implementation to derived classes... If you think it could be useful I will fill enhancement on bugzilla... Or maybe it should be putted for discussion to main D forum? (as it doesn't look like error according to answer)... BR Marcin Kuszczak (aarti_pl)

In full truth, the type information is not completely lost. SpecificStorage s = cast(SpecificStorage)( (new SpeceficStorage).get() ); Or, something more likely to be found: SpecificStorage s; if (auto ref = cast(SpecificStorage)( someObj.foo() )) { s = ref; } else { throw new Exception(...); } And when the new D comes to us... macro Blarg (cls, var, expr, msg) { cls var; if (auto ref = cast(cls)( expr )) { var = ref; } else { throw new Exception(msg); } } // and in code... Blarg(SpecificStorage , s, someObj.foo(), "..."); Blarg(AlternativeStorage, a, someObj.bar(), "..."); Assuming I understand the upcoming macros right... Which if I do, I can't wait for this. -- Chris Nicholson-Sauls
Mar 22 2007
prev sibling next sibling parent Aarti_pl <aarti interia.pl> writes:
Aarti_pl napisał(a):
 
 
 Jarrett Billingsley napisał(a):
 "Aarti_pl" <aarti interia.pl> wrote in message 
 news:ettjqu$14jb$1 digitalmars.com...
 Hello!

 Shouldn't code below work?:

 //-------------------------------------------

 abstract class Storage {
     Storage get() {
         return this;
     }
 }

 class SpecificStorage : Storage {
     void print() {}
 }

 void main() {
     SpecificStorage s = (new SpecificStorage).get();
     s.print;
 }

 //-------------------------------------------

 Unfortunately currently you have to add overridden implementation of 
 get() in SpecificStorage, like below (what is a little bit tedious 
 work):

     SpecificStorage get() {
         return this;
     }


 But my intuition about that would be that "this" pointer from method 
 get from Storage class will point to "SpecificStorage" when there is 
 instantiated SpecificStorage. But it looks that in fact this points 
 to "Storage".

Sounds like it's behaving correctly to me. When you call .get on a SpecificStorage, the only override of it is the one that returns a Storage in the base class, and you can't cast from Storage to SpecificStorage implicitly. The language will not implicitly define covariantly returning versions of your methods for you; that's up to you.

Yes, but in fact I don't want to loose type information and upcast to Storage. I just want to return 'this' as it is when return is invoked. Such a behavior seems a little bit nonsense when there is covariance return type feature in programming language. To get covariance I have many time reimplement same code in every inherited class just to trigger proper behaviour. I think that it should not break anything when instead of making upcasting during return compiler just return concreate type and probably later make upcast when e.g. assigning to Storage variable. It should also not break visibility as I return SpecificStorage - If I would want to return Storage I can make upcast before return even in base class: Storage get() { return cast(Storage)this; } .... But maybe I am wrong... Do you think it would be enhancement for language to have something like this? Or it can break something?... I get to this problem with few simple, guarded setters methods in base class, which should return 'this' to achieve chaining. They should behave exactly same in all derived classes and currently the only way is to copy slightly modified implementation to derived classes... If you think it could be useful I will fill enhancement on bugzilla... Or maybe it should be putted for discussion to main D forum? (as it doesn't look like error according to answer)... BR Marcin Kuszczak (aarti_pl)

Fortunately there are mixins in D, so I can "mix in" covariant functions to derived classes... But I still think it is a little bit hackish... BR Marcin Kuszczak (aarti_pl)
Mar 23 2007
prev sibling parent "Stewart Gordon" <smjg_1998 yahoo.com> writes:
"Aarti_pl" <aarti interia.pl> wrote in message 
news:etu6qm$2251$1 digitalmars.com...
 Jarrett Billingsley napisał(a):
 "Aarti_pl" <aarti interia.pl> wrote in message 
 news:ettjqu$14jb$1 digitalmars.com...
 Hello!

 Shouldn't code below work?:

 //-------------------------------------------

 abstract class Storage {
     Storage get() {
         return this;
     }
 }

 class SpecificStorage : Storage {
     void print() {}
 }

 void main() {
     SpecificStorage s = (new SpecificStorage).get();
     s.print;
 }



 But my intuition about that would be that "this" pointer from method get 
 from Storage class will point to "SpecificStorage" when there is 
 instantiated SpecificStorage. But it looks that in fact this points to 
 "Storage".



 Yes, but in fact I don't want to loose type information and upcast to 
 Storage. I just want to return 'this' as it is when return is invoked.

That's exactly what's happening. You appear to be confusing objects with object references. The object returned is a SpecificStorage, but the object reference is still of type Storage, because that's what the method returns. Before you can assign the reference to a variable of type SpecificStorage, you have to use a cast to make the object reference of type SpecificStorage.
 Such a behavior seems a little bit nonsense when there is covariance 
 return type feature in programming language. To get covariance I have many 
 time reimplement same code in every inherited class just to trigger proper 
 behaviour.

Your example appears contrived - in a real application, you likely wouldn't have a method that simply returns this, and continues to do so for every subclass. You'd just use the object reference directly. If you were to override it to do something different for some classes, then they need not even return an object of the same specific class as that in which it is called. Moreover, there may be a generic programming use case for such things _not_ being implicitly covariant. Stewart.
Mar 29 2007