By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
458,111 Members | 1,665 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 458,111 IT Pros & Developers. It's quick & easy.

Why are there no covariant return types?

P: n/a
Hi,

this code does not compile in C#:

class base_class {}
class derived_class : base_class {}

class A
{
public virtual base_class f()
{
return new base_class();
}
}

class B : A
{
public override derived_class f() // covariant return type
{
return new derived_class();
}
}
Are there any plans to support covariant return types (and maybe
parameter types???) in upcoming C# versions? It could make some OO
designs so much simpler...
Stefan
Nov 16 '05 #1
Share this Question
Share on Google+
14 Replies


P: n/a
Stefan Slapeta <st************@slapeta.com> wrote:

<snip>
Are there any plans to support covariant return types (and maybe
parameter types???) in upcoming C# versions? It could make some OO
designs so much simpler...


I haven't tried it, but I wouldn't be surprised if covariant return
types became available in C#v2, along with generics - I believe in the
Java world, generics made covariance just drop out naturally.

You could always download the .NET v2 beta and try it :)

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 16 '05 #2

P: n/a
Hi Stefan,

Frankly I don't see any use of that.

imagin if you have method like this

void Foo(A a)
{
XXX res = a.f();
}

How can you possibly know what XXX should be. The only sure thing is that
XXX == base_class.
In the current version of C# if you use deriv_class as XXX the compiler will
wmit an error in compile type. With covariant return types it cannot do that
and the error will show up at run time.

So what you and up is code like

base_class res = a.f();
if(res is deriv_class)
{
type cast and use deriv class
}
else
{
use base class
}

or some of its variants. Which is almost what we have now, but imagin if
there is deeper hierarcy.

Or you can use something like
deriv_class res;
try
{
res = a.f()
}
catch(invlid type case exception)
{
}

which is...
You can do that with generics because actually you don't need to use
inheritance and virtual methods, but rather you generate a new type.
--

Stoitcho Goutsev (100) [C# MVP]
"Stefan Slapeta" <st************@slapeta.com> wrote in message
news:cb**********@paperboy.Austria.EU.net...
Hi,

this code does not compile in C#:

class base_class {}
class derived_class : base_class {}

class A
{
public virtual base_class f()
{
return new base_class();
}
}

class B : A
{
public override derived_class f() // covariant return type
{
return new derived_class();
}
}
Are there any plans to support covariant return types (and maybe
parameter types???) in upcoming C# versions? It could make some OO
designs so much simpler...
Stefan

Nov 16 '05 #3

P: n/a
Stoitcho Goutsev (100) [C# MVP] wrote:
Frankly I don't see any use of that.
This concept (covariance) is supported by a wide range of programming
languages and opens a wide range of possibilities in OO design.
imagin if you have method like this

void Foo(A a)
{
XXX res = a.f();
}

How can you possibly know what XXX should be. The only sure thing is that
XXX == base_class.
Yes, this amount of knowledge is the fundamental idea of what is named
'polymorphism'.
In the current version of C# if you use deriv_class as XXX the compiler will
wmit an error in compile type. With covariant return types it cannot do that
and the error will show up at run time.


No, it will not, of course. It's the same as

BaseClass bc = new Derived();

I just wonder why this quite simple concept is not implemented in C#:
IMO it _must_ be implemented in the CIL (at least in 2.0) because
covariant return types supported by C++.

Stefan
Nov 16 '05 #4

P: n/a
Could you give us some real life example of where you could use that.
And frankly I don't see how c++ supports that. I would say that c++ may not
check the return type when overriding methods, but to support it I really
doubt it.

Would you say that c# supports covariant return types if it doesn't report
an error? Because honestly I don't see what more it can you do about it.
Yes, you may say that the CLR supports covariant return types because it
simply doesn't check the type of the return value for method overriding and
overloading.
--

Stoitcho Goutsev (100) [C# MVP]
"Stefan Slapeta" <st************@slapeta.com> wrote in message
news:cb**********@paperboy.Austria.EU.net...
Stoitcho Goutsev (100) [C# MVP] wrote:
Frankly I don't see any use of that.


This concept (covariance) is supported by a wide range of programming
languages and opens a wide range of possibilities in OO design.
imagin if you have method like this

void Foo(A a)
{
XXX res = a.f();
}

How can you possibly know what XXX should be. The only sure thing is that XXX == base_class.


Yes, this amount of knowledge is the fundamental idea of what is named
'polymorphism'.
In the current version of C# if you use deriv_class as XXX the compiler will wmit an error in compile type. With covariant return types it cannot do that and the error will show up at run time.


No, it will not, of course. It's the same as

BaseClass bc = new Derived();

I just wonder why this quite simple concept is not implemented in C#:
IMO it _must_ be implemented in the CIL (at least in 2.0) because
covariant return types supported by C++.

Stefan

Nov 16 '05 #5

P: n/a
Stoitcho Goutsev (100) [C# MVP] wrote:
Could you give us some real life example of where you could use that.
And frankly I don't see how c++ supports that. I would say that c++ may not
check the return type when overriding methods, but to support it I really
doubt it.


ok, here is a living example in C++ which is not implementable in C#. I
think it explaines itself, if not, just compile and debug it. For
further information where this makes sense: http://tinyurl.com/2s6zp

#include <iostream>

class base {
public:
virtual void g() const {
std::cout << "base" << std::endl;
}
};
class derived : public base {
public:
virtual void g() const {
std::cout << "derived" << std::endl;
}
};

class A {
base m_base;
public:
virtual base const& f() {
return m_base;
}
};

class B : public A {
derived m_derived;
public:
virtual derived const& f() {
return m_derived;
}
};

void some_function(A& a)
{
a.f().g();
}

int main()
{
B b;
some_function(b);
}

Nov 16 '05 #6

P: n/a
See there is my point if you change in class B the method *f* to return
*base* isnted of derived the result will be the same. So you have no
advantages using covariant return types.

As it goes for the example you post. Those are not managed classes. From the
CLR perspective (if you use ILDasm you can see) those are value types and
are not releated with any inheritance.

If you make them managed classes (*__gc*) and fix all the errors that the
compiler reports you will end up with one error # C2392 that says:

'method' : covariant returns types are not supported in managed types

Anyways I still don't see any advantage using them. Anything, but
porortunity for a bug to creep into my release version.
--

Stoitcho Goutsev (100) [C# MVP]
"Stefan Slapeta" <st************@slapeta.com> wrote in message
news:cb**********@paperboy.Austria.EU.net...
Stoitcho Goutsev (100) [C# MVP] wrote:
Could you give us some real life example of where you could use that.
And frankly I don't see how c++ supports that. I would say that c++ may not check the return type when overriding methods, but to support it I really doubt it.


ok, here is a living example in C++ which is not implementable in C#. I
think it explaines itself, if not, just compile and debug it. For
further information where this makes sense: http://tinyurl.com/2s6zp

#include <iostream>

class base {
public:
virtual void g() const {
std::cout << "base" << std::endl;
}
};
class derived : public base {
public:
virtual void g() const {
std::cout << "derived" << std::endl;
}
};

class A {
base m_base;
public:
virtual base const& f() {
return m_base;
}
};

class B : public A {
derived m_derived;
public:
virtual derived const& f() {
return m_derived;
}
};

void some_function(A& a)
{
a.f().g();
}

int main()
{
B b;
some_function(b);
}

Nov 16 '05 #7

P: n/a
Stoitcho Goutsev (100) [C# MVP] <10*@100.com> wrote:
Could you give us some real life example of where you could use that.


Here's a *really* simple example: ICloneable.

ICloneable defines Clone's return type to be object, when actually you
almost *always* end up casting the result to the type you know it will
be - the same type as the instance you're calling it on.

So, if I want to clone an ArrayList, I need:

ArrayList copy = (ArrayList) original.Clone();

If ArrayList could have declared

ArrayList Clone()
{
....
}

we wouldn't need to do this.

Now in fact, this *is* done all over the framework already, using
explicit interface implementation - look at the various database
classes (SqlConnection, SqlCommand etc). It's a nasty hack around the
lack of covariant return types, and it would have been much nicer if a
single method could have been declared, instead of one for the generic
version and one for the concrete subtype.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 16 '05 #8

P: n/a
Yeah, besides the fact that theoretically you don't know the type of the
object, which Clone methods you call.

And again in theory one should go with the most generic base type and then
do the conversion.

---
Stoitcho Goutsev (100) [C# MVP]
"Jon Skeet [C# MVP]" <sk***@pobox.com> wrote in message
news:MP************************@msnews.microsoft.c om...
Stoitcho Goutsev (100) [C# MVP] <10*@100.com> wrote:
Could you give us some real life example of where you could use that.


Here's a *really* simple example: ICloneable.

ICloneable defines Clone's return type to be object, when actually you
almost *always* end up casting the result to the type you know it will
be - the same type as the instance you're calling it on.

So, if I want to clone an ArrayList, I need:

ArrayList copy = (ArrayList) original.Clone();

If ArrayList could have declared

ArrayList Clone()
{
...
}

we wouldn't need to do this.

Now in fact, this *is* done all over the framework already, using
explicit interface implementation - look at the various database
classes (SqlConnection, SqlCommand etc). It's a nasty hack around the
lack of covariant return types, and it would have been much nicer if a
single method could have been declared, instead of one for the generic
version and one for the concrete subtype.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too

Nov 16 '05 #9

P: n/a

"Jon Skeet [C# MVP]" <sk***@pobox.com> wrote in message
news:MP************************@msnews.microsoft.c om...
Stefan Slapeta <st************@slapeta.com> wrote:

<snip>
Are there any plans to support covariant return types (and maybe
parameter types???) in upcoming C# versions? It could make some OO
designs so much simpler...


I haven't tried it, but I wouldn't be surprised if covariant return
types became available in C#v2, along with generics - I believe in the
Java world, generics made covariance just drop out naturally.


Java actually uses a different mechanism for covariants, one that's so
simple that the generated bytecode works in JVMs back to (at least) 1.3,
though the 1.5 compiler is the first to allow the syntax.

class Base { Object foo() { ...} }
class Derived extends Base { String foo() {...} }

is compiled as if Derived also defined a method

Object foo() { return String-version-of-foo(); }

This makes the dispatch of Base.foo() do the right thing.
Nov 16 '05 #10

P: n/a
Stoitcho Goutsev (100) [C# MVP] wrote:
Yeah, besides the fact that theoretically you don't know the type of the
object, which Clone methods you call.

And again in theory one should go with the most generic base type and then
do the conversion.


In theory, you should avoid any cast if possible because every cast is a
potential runtime error!

And here - *with* covariant return types - you *for sure* know what
class you are dealing with *and* you can avoid any cast.

ArrayList original;
ArrayList copy = original.Clone();
Stefan
Nov 16 '05 #11

P: n/a
Stoitcho Goutsev (100) [C# MVP] wrote:

'method' : covariant returns types are not supported in managed types

And so I would be interested whether they are supported in C# 2.0; I
think they _are_ in the C++.net release.
Anyways I still don't see any advantage using them. Anything, but
porortunity for a bug to creep into my release version.


I think there you have not understood this concept so far: using
covariant return types _can not_ lead to errors you don't also get
without them!

Stefan
Nov 16 '05 #12

P: n/a
Stoitcho Goutsev (100) [C# MVP] wrote:
See there is my point if you change in class B the method *f* to return
*base* isnted of derived the result will be the same. So you have no
advantages using covariant return types.


I know what you mean - maybe the example was not the best. Covariant
return types of coure only make sense if you deal *not only* with the
base class (or any interface), but also with the (return types of the)
derived class. Jon's example maybe provides the best possible explanation.

Stefan
Nov 16 '05 #13

P: n/a
On Fri, 02 Jul 2004 11:38:49 +0200, Stefan Slapeta
<st************@slapeta.com> wrote:
And so I would be interested whether they are supported in C# 2.0; I
think they _are_ in the C++.net release.


Hi Stefan:

Putting the code from your original post into Beta 1 of the 2005
compiler produces:

'Testt.B.f()': return type must be 'Test.base_class' to match
overridden member 'Test.A.f()'

--
Scott
http://www.OdeToCode.com
Nov 16 '05 #14

P: n/a
Hmm, there are always cases where something can be useful. I said in theory
becuse I can't see any possible way to know what is the type in this
situation

void Foo(ArrayList list)
{
XXX copy = list.Clone();

//What is XXX? The simple answer is ArrayList. But is it?

}

A dont see many cases where you create a list and cloned. Normaly you
received as a parameter or it is property of some object. In this case you
cannot know.
--

Stoitcho Goutsev (100) [C# MVP]
"Stefan Slapeta" <st************@slapeta.com> wrote in message
news:cc**********@paperboy.Austria.EU.net...
Stoitcho Goutsev (100) [C# MVP] wrote:
Yeah, besides the fact that theoretically you don't know the type of the
object, which Clone methods you call.

And again in theory one should go with the most generic base type and then do the conversion.


In theory, you should avoid any cast if possible because every cast is a
potential runtime error!

And here - *with* covariant return types - you *for sure* know what
class you are dealing with *and* you can avoid any cast.

ArrayList original;
ArrayList copy = original.Clone();
Stefan

Nov 16 '05 #15

This discussion thread is closed

Replies have been disabled for this discussion.