user1058272
user1058272

Reputation: 113

subtype and covariant return type

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

Answers (6)

Eric Lippert
Eric Lippert

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

Lukazoid
Lukazoid

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

Jon Skeet
Jon Skeet

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

Ravi Bhatt
Ravi Bhatt

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

JaredPar
JaredPar

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

Alok Save
Alok Save

Reputation: 206566

Your understanding would be correct if and only if TypeY is derived from TypeX.

Upvotes: 1

Related Questions