Reputation: 113
I found an explanation What is a covariant return type? but I am no smart to understand it all.
I think Covariant return type theoritically is the type returned by a function that has the same signature with a built-in base class function whose return type is different.
class Base{
TypeX func( int i ){return typex;} // builtin function
};
class Derived:Base{
TypeY func(int i){return typey;}
}
Is my understanding of this so-called covariant return type correct ? [the term really confuses me.]
Upvotes: 2
Views: 1502
Reputation: 660289
This would be an example of covariant return types:
class Food {}
class Fruit : Food {}
class FoodEater
{
public virtual Food GetFavouriteFood() { ... }
}
class FruitEater : FoodEater
{
public override Fruit GetFavouriteFood() { ... }
}
In languages that support return type covariance, this would be legal. That is a method that returns a Food can be overridden by a method that returns a Fruit, because Fruit is a kind of Food. It is called "covariance" because the "variance" is in the same direction:
A Fruit may be used as a Food, therefore:
A Fruit-returning-method may be used as a Food-returning-method
See how the variance is in the same direction?
Contrast that with parameter type contravariance:
class Food {}
class Fruit : Food {}
class Apple : Fruit {}
class Orange : Fruit {}
class Cake : Food {}
class FruitComparer
{
public virtual bool Compare(Fruit f1, Fruit f2) { ... }
}
class FoodComparer : FruitComparer
{
public override bool Compare(Food f1, Food f2) { ... }
}
A FruitComparer can compare Apples to Oranges. A FoodComparer can also compare Apples to Oranges, but can compare even more -- it can compare Apples to Cakes, or Cakes to Oranges, or whatever.
In languages that support parameter type contravariance, this is legal. See how the variance directions are now reversed:
A Fruit may be used as a Food, therefore
A Food-taking-method may be used as a Fruit-taking-method
Now the relationship has gone backwards, so it is contravariant.
C# supports neither kind of method variance for virtual overloading. Virtual method overrides must match exactly. However, C# does support both kinds of method variance for method group to delegate conversions, and for generic delegate type conversions.
Upvotes: 6
Reputation: 19426
Unlike java, covariant return types are not supported in C#. I believe this is due to the implementation of C# properties, if covariant return types were allowed, the following would be possible:
class TypeX { }
class TypeY : TypeX { }
class Base
{
public virtual TypeX Prop { get; set; }
}
class Derived : Base
{
public override TypeY Prop { get; set; }
}
Derived derived = new Derived();
derived.Prop = new TypeY(); // Valid
Base @base = derived;
@base.Prop = new TypeX(); // Invalid - As this would be using the derived property which should be of TypeY
See Eric Lippert's answer for more information.
Upvotes: 3
Reputation: 1502106
The ability to use covariant return types in Java is what you've just demonstrated, yes - assuming that TypeY
is a subclass of TypeX
. The point is that any callers who only "know" about the signature specified in Base
are still okay, because any TypeY
returned by the Derived
implementation is still a valid TypeX
reference. Note that it does only work for reference types (classes) - it wouldn't be valid to use:
// In the base class
long func() { ... }
// In the derived class
@Override int func() { ... }
... even though there's an implicit conversion from int
to long
, and int
value isn't in itself a long
value. There isn't the same representational validity that there is for references (where a String
reference is an Object
reference - if you know that a particular set of bits is a String
reference, you can treat those exact same bits as an Object
reference.).
C# does not support covariant return types, but as of C# 4 it does support generic variance as declared on interfaces and delegates. For example, IEnumerable<T>
is declared in .NET 4 as
public interface IEnumerable<out T> { ... }
The out
shows that T
is covariant in the interface, which means this conversion is valid:
IEnumerable<string> strings = ...;
IEnumerable<object> objects = strings;
The reverse assignment would not be valid, as a sequence of arbirary object
references may not be a valid sequence of string
references.
For more on this topic, see MSDN (or do a search for c# generic variance).
Upvotes: 0
Reputation: 3163
A co-variant return type is a way to return a "narrower" type from a function. The "narrower" type would be the subclass of the original return type.
class A {
}
class B extends A {
}
// Classes demonstrating method overriding:
class C {
A getFoo() {
return new A();
}
}
class D extends C {
B getFoo() {
return new B();
}
}
The fact that we could return a B
from getFoo()
is a co-variant return. Its important to note that while overriding
you are not allowed to change return type, but with java 5.0
a co-variant type is allowed.
Upvotes: 1
Reputation: 755141
The feature which allows this type of overloading is known as covariant return types iff TypeY
is a subtype of TypeX
. Wikipedia has a nice discussion of the feature
Upvotes: 0
Reputation: 206566
Your understanding would be correct if and only if TypeY
is derived from TypeX
.
Upvotes: 1