5

I'm not clear on the concept of Covariance in C# when it comes to interfaces. Strictly based on my example below, is this an example of Covariance, please describe why or why not.

class Program
{
    static void Main()
    {
        ICarInterface car = new Car();
    }
}

interface ICarInterface
{
    void Start();
}

class Car : ICarInterface
{
    public void Start()
    {

    }
}
Exocomp
  • 1,477
  • 2
  • 20
  • 29
  • No this is not. It's related to generics. There are plenty of questions on it on SO already. – nawfal Jun 19 '16 at 12:45
  • I don't get it though, why is it related strictly to Generics? In my example, Car inherits from ICarInterface. So isn't the following an implicit upcast which would mean it is an example Covariance? What am I missing? ICarInterface car = new Car(); – Exocomp Jun 19 '16 at 12:50
  • This is ***not*** a duplicate. Exocomp is asking if *the specific code he shows* is an example of covariance (and why/why not), not for a big ol' list of "real world examples" of covariance. It *might* be a duplicate of a question that explains what covariance is, but that's not the one that was picked. Reopening... – Cody Gray - on strike Jun 19 '16 at 18:22

3 Answers3

3

Covariance is related to the interplay of subtyping and generics. As your program does not involve generics, it is not an example of covariance.

If U is a subtype of V (e.g. U = Pear and V = Fruit), then a generic type G<T> is said to be covariant in T if G<U> is a subtype of G<V>. For example, IEnumerable<Pear> is a subtype of IEnumerable<Fruit>: something that you can take pears from can be used to take fruit from.

If G reverses the subtyping relation (G<V> is a subtype of G<U>), it is said to be contravariant in T. For instance, Action<Fruit> is a subtype of Action<Pear>: something that you can put fruit in can be used to put pears in.

In your example, neither ICarInterface nor Car has a type parameter that it could be covariant in.

Specifically, in C#, a generic type is covariant in a type parameter T if T is marked with out. It is contravariant in T if T is marked with in.

Ruud
  • 3,118
  • 3
  • 39
  • 51
  • >>"Covariance is related to the interplay of subtyping and generics" What about array covariance in C# 1, generics didn't exist then so that makes your statement not entirely correct. To sum up your response your saying that in order to have Covariance you need to have a generic collection/list ? So because my example does not have a generic collection/list it does not have Covariance ? – Exocomp Jun 19 '16 at 14:02
  • 1
    C# did not have generics at the time, so the specific case of arrays was hard-coded. Essentially, array *is* a generic type: instead of `T[]` you could read `Array`. (The actual `Array` class is not generic; this is a historical artefact, just like the non-generic `IList` and `ArrayList`.) Array covariance here means that `Pear[]` is a subtype of `Fruit[]`. It is analogous to the case of `IEnumerable`. (Note that array covariance is dangerous, as it means you can put an `Orange` in a `Fruit[]` which is actually a `Pear[]`. This is avoided by runtime checks.) – Ruud Jun 19 '16 at 14:53
  • Also, covariance and contravariance are not limited to generic collections. For instance `Func` is covariant in `TResult` and contravariant in `T`. Covariance and contravariance are properties of the type parameters. As there are no type parameters in your example, there is nothing that *could* be covariant. – Ruud Jun 19 '16 at 14:59
1

No, this is not really covariance. This is just the implementation of an interface. Specifically, it is an example of assignment compatibility. Because the Car class implements the ICarInterface interface, a Car object can be assigned to a variable of type ICarInterface. An object of a more-specific type (Car) was assigned to a storage area for a less-specific type (ICarInterface), which works because the two types are compatible for the purposes of assignment.

Covariance is a slightly different thing. A type relationship is covariant if it preserves the ordering of types (from the more-specific to the more-generic). For example, IEnumerable<T> is covariant with respect to type T, so it preserves the ordering of types IEnumerable<Vehicle> (more-generic) and IEnumerable<Car> (more-specific). (In this example, we are of course assuming that Car is a subclass of Vehicle).

Eric Lippert has written an excellent article that distinguishes between covariance and assignment-compatibility. It gets slightly technical and theoretical, but you should definitely read it. I would not do it justice by trying to summarize it any further here.


An easier-to-understand example of covariance (at least in my opinion) is return-type covariance. This is where a derived class's override of a base-class method returns a more specific type. For example:

abstract class Habitat
{
    public abstract Animal ApexPredator();
}

class Savanna : Habitat
{
    public override Lion ApexPredator()
    { ... }
}

class Ocean : Habitat
{
    public override Shark ApexPredator()
    { ... }
}

In this example, the abstract class Habitat has two concrete subclasses: Savanna and Ocean. All habitats have an ApexPredator, which is of type Animal. But in a Savanna object, the apex predator is a Lion, whereas in an Ocean object, the apex predator is a Shark. This is legal and safe because Lion and Shark are both types of Animals.

Unfortunately, C# does not support return type covariance. It is, however, supported by C++ (including C++/CLI), Java, and a number of other object-oriented languages.

Here are some more concrete examples of covariance.

Community
  • 1
  • 1
Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
  • Hi Cody, your example regarding C# not supporting return type covariance had me thinking for a bit and I see what your saying specifically in that example. I guess you can solve that problem using Generics. Using a placeholder for the return type but anyway not to get off too much off topic. My question was really why my example was not Covariance, you say that is an example of "Assignment Compatibility" but it doesn't explain why it's not Covariance? Is it possible that "Assignment Compatibility" is Covariance but not all Covariance is "Assignment Compatibility" ? – Exocomp Jun 19 '16 at 13:52
  • @exo Well no, you wouldn't really want to use generics as a substitute for return-type covariance. Generics would imply no relationship between the types, when a relationship is the whole point of return-type covariance. The standard way of emulating return-type covariance in C# is method hiding. Make the override method `protected`, and then add a `public` method that hides (`new`) the overridden method. If you have more questions about that, you should ask a new question. – Cody Gray - on strike Jun 19 '16 at 14:07
  • @exo As for your other questions... *"My question was really why my example was not Covariance, you say that is an example of "Assignment Compatibility" but it doesn't explain why it's not Covariance?"* Did you read the linked blog post? It does a very good job of explaining the difference between the two. What part did you not understand? *"Is it possible that "Assignment Compatibility" is Covariance but not all Covariance is "Assignment Compatibility" ?"* No, they are distinct concepts. You might say that assignment compatibility is preserved in a covariant relationship, though. – Cody Gray - on strike Jun 19 '16 at 14:08
  • You've given me some things to think about, let me review and will follow up. – Exocomp Jun 19 '16 at 14:13
  • 1
    @Exocomp: Parametric polymorphism covariance is related to assignment compatibility because *assignment compatibility is the relation that is preserved across the generic type mapping*. But they are not at all the same thing. One is a rule for when an assignment is legal, the other is *a pattern for generating new rules for when assignments are legal*. A pattern for making more dresses and a dress are two different things. – Eric Lippert Jun 20 '16 at 13:11
0

This is not an example of covariance, it is just a simple example of polymorphism. Here you can find the differences between covariance and polymorphism

Community
  • 1
  • 1
meJustAndrew
  • 6,011
  • 8
  • 50
  • 76
  • I went to the link you gave it has examples using .NET 4 and to be honest doesn't answer why my example is not an example of Covariance. – Exocomp Jun 19 '16 at 13:02