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
98
votes
15 answers

C#: Overriding return types

Is there way to override return types in C#? If so how, and if not why and what is a recommended way of doing it? My case is that I have an interface with an abstract base class and descendants of that. I would like to do this (ok not really, but as…
Svish
  • 152,914
  • 173
  • 462
  • 620
94
votes
2 answers

Understanding Covariant and Contravariant interfaces in C#

I've come across these in a textbook I am reading on C#, but I am having difficulty understanding them, probably due to lack of context. Is there a good concise explanation of what they are and what they are useful for out there? Edit for…
NibblyPig
  • 51,118
  • 72
  • 200
  • 356
89
votes
4 answers

Why is Task not co-variant?

class ResultBase {} class Result : ResultBase {} Task GetResult() { return Task.FromResult(new Result()); } The compiler tells me that it cannot implicitly convert Task to Task. Can someone explain why this is?…
chosenbreed37
  • 1,292
  • 9
  • 10
86
votes
14 answers

In C#, why can't a List object be stored in a List variable
It seems that a List object cannot be stored in a List variable in C#, and can't even be explicitly cast that way. List sl = new List(); List ol; ol = sl; results in Cannot implicitly convert type…
Matt Sheppard
  • 116,545
  • 46
  • 111
  • 131
83
votes
2 answers

scala - Any vs underscore in generics

What is the different between the following Generics definitions in Scala: class Foo[T <: List[_]] and class Bar[T <: List[Any]] My gut tells me they are about the same but that the latter is more explicit. I am finding cases where the former…
Sean Connolly
  • 5,692
  • 7
  • 37
  • 74
80
votes
7 answers

How can I use covariant return types with smart pointers?

I have code like this: class RetInterface {...} class Ret1: public RetInterface {...} class AInterface { public: virtual boost::shared_ptr get_r() const = 0; ... }; class A1: public AInterface { public: …
amit kumar
  • 20,438
  • 23
  • 90
  • 126
76
votes
3 answers

Calculating Covariance with Python and Numpy

I am trying to figure out how to calculate covariance with the Python Numpy function cov. When I pass it two one-dimentional arrays, I get back a 2x2 matrix of results. I don't know what to do with that. I'm not great at statistics, but I believe…
Dave
  • 1,326
  • 2
  • 11
  • 22
73
votes
4 answers

Is there a generic Task.WaitAll?

I start a few parallel tasks, like this: var tasks = Enumerable.Range(1, 500) .Select(i => Task.Factory.StartNew(ProduceSomeMagicIntValue)) .ToArray(); and then join them with Task.WaitAll(tasks); On this last line I get a blue…
Cristian Lupascu
  • 39,078
  • 16
  • 100
  • 137
70
votes
4 answers

C# variance problem: Assigning List as List

Look at the following example (partially taken from MSDN Blog): class Animal { } class Giraffe : Animal { } static void Main(string[] args) { // Array assignment works, but... Animal[] animals = new Giraffe[10]; // implicit... …
AndiDog
  • 68,631
  • 21
  • 159
  • 205
65
votes
7 answers

still confused about covariance and contravariance & in/out

ok i read a bit on this topic on stackoverflow, watched this & this, but still a bit confused about co/contra-variance. from here Covariance allows a "bigger" (less specific) type to be substituted in an API where the original type is only …
Jiew Meng
  • 84,767
  • 185
  • 495
  • 805
64
votes
6 answers

Difference between covariance and upcasting

What is the difference between covariance and upcasting, or, more specifically, why are they given different names? I've seen the following example referred to as 'upcasting': string s = "hello"; object o = s; //upcast to 'string' to…
James Wiseman
  • 29,946
  • 17
  • 95
  • 158
63
votes
6 answers

IDictionary in .NET 4 not covariant

The IDictionary in .NET 4 / Silverlight 4 does not support covariance, i.e. I can't do a IDictionary myDict = new Dictionary(); analog to what I can do with IEnumerables now. Probably boils down to…
herzmeister
  • 11,101
  • 2
  • 41
  • 51
61
votes
3 answers

Why aren't there many discussions about co- and contra-variance in Haskell (as opposed to Scala or C#)?

I know what covariance and contravariance of types are. My question is why haven't I encountered discussion of these concepts yet in my study of Haskell (as opposed to, say, Scala)? It seems there is a fundamental difference in the way Haskell views…
ErikR
  • 51,541
  • 9
  • 73
  • 124
57
votes
4 answers

Why are Arrays invariant, but Lists covariant?

E.g. why does val list:List[Any] = List[Int](1,2,3) work, but val arr:Array[Any] = Array[Int](1,2,3) fails (because arrays are invariant). What is the desired effect behind this design decision?
fresskoma
  • 25,481
  • 10
  • 85
  • 128
57
votes
3 answers

Is C# type system sound and decidable?

I know that Java's type system is unsound (it fails to type check constructs that are semantically legal) and undecidable (it fails to type check some construct). For instance, if you copy/paste the following snippet in a class and compile it, the…
Norswap
  • 11,740
  • 12
  • 47
  • 60