Questions tagged [covariance]

Covariance, contravariance and invariance describe how the existing type inheritance hierarchy changes when subjected to some transformation (such as usage within generics). If the transformation keeps the ordering of the original hierarchy, it is "covariant". If it reverses it, it is "contravariant". If it breaks it, it is "invariant".

About Type Ordering

Let's say that a class P (parent) is inherited by a class C (child).

We can denote this fact as: P > C.

Informally, P is "larger" than C since it "contains" all the possible instances of C, but can also contain some other instances that are not C. Child is always parent but not necessarily the other way around.

Variance in Generics

Let's say that there is a generic type G that has a single generic parameter T, denoted by: G{T}.

  • If G{P} > G{C}, then T is co-variant (it preserves the original inheritance ordering).
  • If G{P} < G{C}, then T is contra-variant (it reverses the original inheritance ordering).
  • If G{P} and G{C} are type-unrelated, then T is invariant (it "breaks" the inheritance).

So the variance is the property of transformation (in this case: generic parameter T of G), not the original type hierarchy (P and C).

C# Examples

The generic parameter T of IEnumerable<out T> is covariant (as denoted by "out" keyword), meaning you can "forget" that the collection contains Cs and just treat it as if it contains Ps. For example:

IEnumerable<C> ec = ...;
IEnumerable<P> ep = ec;

The generic parameter T of Action<in T> is contravariant (as denoted by "in" keyword), meaning that an action that accepts P can also accept C. For example:

Action<P> ap = ...;
Action<C> ac = ap;

The generic parameter T is contravariant and generic parameter TResult is covariant in Func<in T, out TResult>. Each generic parameter is considered a different "transformation" with its own variance. This lets you write a code like this:

Func<P, C> fpc = ...;
Func<C, P> fcp = fpc;

And finally, the generic parameter T of IList<T> is considered invariant, so IList<P> and IList<C> are considered unrelated types (there is no assignment compatibility in either direction).


Tag usage

  • Do not use for the measurement of the strength and direction of the linear relationship between two random variables (statistical context). Instead, use other related tags, for example, .
    Moreover, consider whether the question might be better suited to Cross Validated, the Stack Exchange site for statistics, machine learning and data analysis.
1905 questions
54
votes
4 answers

Covariance and IList

I would like a Covariant collection whose items can be retrieved by index. IEnumerable is the only .net collection that I'm aware of that is Covariant, but it does not have this index support. Specifically, I'd like to do this: List dogs = new…
Brian M
  • 553
  • 1
  • 4
  • 6
53
votes
3 answers

Generics : List is same as List?

I am just trying to understand the extends keyword in Java Generics. List means we can stuff any object in the List which IS A Animal then won't the following also mean the same thing: List Can someone help me know the…
peakit
  • 28,597
  • 27
  • 63
  • 80
47
votes
1 answer

Python typing what does TypeVar(A, B, covariant=True) mean?

Today I took a deep dive into Liskov's Substitution Principle and covariance/contravariance. And I got stuck on the difference between: T = TypeVar("T", bound=Union[A, B]) T = TypeVar("T", A, B, covariant=True) My Understanding of #1 Difference…
Intrastellar Explorer
  • 3,005
  • 9
  • 52
  • 119
46
votes
3 answers

T must be contravariantly valid

What is wrong with this? interface IRepository where T : IBusinessEntity { IQueryable GetAll(); void Save(T t); void Delete(T t); } It says: Invalid variance: The type parameter 'T' must be contravariantly valid on…
Eduardo
  • 5,645
  • 4
  • 49
  • 57
46
votes
9 answers

Can I Override with derived types?

As far as i know it is not possible to do the following in C# 2.0 public class Father { public virtual Father SomePropertyName { get { return this; } } } public class Child : Father { public…
Luis Filipe
  • 8,488
  • 7
  • 48
  • 76
44
votes
3 answers

Why was IEnumerable made covariant in C# 4?

In earlier versions of C# IEnumerable was defined like this: public interface IEnumerable : IEnumerable Since C# 4 the definition is: public interface IEnumerable : IEnumerable Is it just to make the annoying casts in LINQ expressions…
soc
  • 27,983
  • 20
  • 111
  • 215
44
votes
5 answers

Generic type parameter covariance and multiple interface implementations

If I have a generic interface with a covariant type parameter, like this: interface IGeneric { string GetName(); } And If I define this class hierarchy: class Base {} class Derived1 : Base{} class Derived2 : Base{} Then I can implement…
SWeko
  • 30,434
  • 10
  • 71
  • 106
44
votes
5 answers

C# : Is Variance (Covariance / Contravariance) another word for Polymorphism?

I am trying to figure out the exact meaning of the words Covariance and Contravariance from several articles online and questions on StackOverflow, and from what I can understand, it's only another word for polymorphism. Am I correct with the above…
Andreas Grech
  • 105,982
  • 98
  • 297
  • 360
42
votes
3 answers

Simple examples of co and contravariance

Could someone provide me simple C# examples of convariance, contravariance, invariance and contra-invariance (if such thing exists). All samples I've seen so far was just casting some object into System.Object.
Grant Smith
  • 755
  • 2
  • 6
  • 11
42
votes
5 answers

Contravariance explained

First of, I have read many explanations on SO and blogs about covariance and contravariance and a big thanks goes out to Eric Lippert for producing such a great series on Covariance and Contravariance. However I have a more specific question that I…
Stan R.
  • 15,757
  • 4
  • 50
  • 58
41
votes
2 answers

C# variance annotation of a type parameter, constrained to be value type

It is possible in C# to add variance annotation to type parameter, constrained to be value type: interface IFoo where T : struct { void Boo(T x); } Why is this allowed by compiler if variance annotation makes completely no sense in a such…
controlflow
  • 6,667
  • 1
  • 31
  • 55
39
votes
1 answer

What makes ValueTuple covariant?

This compiles correctly in C# 7.3 (Framework 4.8): (string, string) s = ("a", "b"); (object, string) o = s; I know that this is syntactic sugar for the following, which also compiles correctly: ValueTuple s = new ValueTuple
Heinzi
  • 167,459
  • 57
  • 363
  • 519
38
votes
2 answers

Is this a covariance bug in C# 4?

In the following piece of code I expected to be able to implicitly cast from elements to baseElements because TBase is implicitly convertible to IBase. public interface IBase { } public interface IDerived : IBase { } public class VarianceBug { …
Omer Mor
  • 5,216
  • 2
  • 34
  • 39
37
votes
7 answers

Why doesn't this generic extension method compile?

The code is a little weird, so bear with me (keep in mind this scenario did come up in production code). Say I've got this interface structure: public interface IBase { } public interface IChild : IBase { } public interface IFoo where T :…
Cameron
  • 96,106
  • 25
  • 196
  • 225
37
votes
4 answers

Co- and Contravariance bugs in .NET 4.0

Some strange behavior with the C# 4.0 co- and contravariance support: using System; class Program { static void Foo(object x) { } static void Main() { Action action = _ => { }; // C# 3.5 supports static co- and contravariant…
controlflow
  • 6,667
  • 1
  • 31
  • 55