Thread overview
Covariant return type
Mar 22, 2007
Aarti_pl
Mar 22, 2007
Aarti_pl
Mar 23, 2007
Aarti_pl
Mar 29, 2007
Stewart Gordon
March 22, 2007
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)
March 22, 2007
"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.


March 22, 2007

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)
March 22, 2007
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
March 23, 2007
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)
March 29, 2007
"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;
>>> }
<snip>
>>> 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".
<snip>
> 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.
<snip>

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.