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
21
votes
6 answers

C++ covariant templates

I feel like this one has been asked before, but I'm unable to find it on SO, nor can I find anything useful on Google. Maybe "covariant" isn't the word I'm looking for, but this concept is very similar to covariant return types on functions, so I…
rmeador
  • 25,504
  • 18
  • 62
  • 103
21
votes
2 answers

Why generic interfaces are not co/contravariant by default?

For example IEnumerable interface: public interface IEnumerable : IEnumerable { IEnumerator GetEnumerator(); } In this interface the generic type is used only as a return type of interface method and not used as a type of method…
Konstantin Tarkus
  • 37,618
  • 14
  • 135
  • 121
21
votes
3 answers

How to find the minimum covariant type for best fit between two types?

There's IsAssignableFrom method returns a boolean value indicates if one type is assignable from another type. How can we not only test if they are assignable from or to each other, but also know the minimum covariant type for best fit? Consider…
Ken Kin
  • 4,503
  • 3
  • 38
  • 76
20
votes
2 answers

Var(x) and cov(x, x) don't give the same result in numpy

A property of the covariance is, that cov(x, x) = var(x) However, in numpy I don't get the same result. from numpy import var, cov x = range(10) y = var(x) z = cov(x, x)[0][1] print y, z Am I doing something wrong here? How can I obtain the…
Randomtheories
  • 1,220
  • 18
  • 22
20
votes
1 answer

Generic wildcards in variable declarations in Scala

In Java I might do this: class MyClass { private List list; public void setList(List l) { list = l; } } ...assuming that (MyImpl implements MyInterface) of course. What is the analog for this in Scala, when…
oxbow_lakes
  • 133,303
  • 56
  • 317
  • 449
20
votes
2 answers

OCaml variance (+'a, -'a) and invariance

After writing this piece of code module type TS = sig type +'a t end module T : TS = struct type 'a t = {info : 'a list} end I realised I needed info to be mutable. I wrote, then : module type TS = sig type +'a t end module T : TS =…
Lhooq
  • 4,281
  • 1
  • 18
  • 37
20
votes
3 answers

Faster way to cast a Func to Func?

Is there a faster way to cast Fun to Func public static class StaticAccessors { public static Func TypedGetPropertyFn(PropertyInfo pi) { var mi = pi.GetGetMethod(); return…
mythz
  • 141,670
  • 29
  • 246
  • 390
20
votes
1 answer

Shouldn't ILookup be (declared) covariant in TElement?

The definition System.Linq.ILookUp reads interface ILookup : IEnumerable>, IEnumerable { int Count { get; } IEnumerable this[TKey key] { get; } bool Contains(TKey…
bigge
  • 1,488
  • 15
  • 27
20
votes
1 answer

covariant type T occurs in contravariant position

I know this question has been asked before, but either the answers don't apply to this case, or I don't understand them. Basically, why doesn't the following (simple example that recreates my problem) work ? class Test[+T] { var list: List[T] =…
sksamuel
  • 16,154
  • 8
  • 60
  • 108
20
votes
2 answers

C# casting an inherited Generic interface

I'm having some trouble getting my head around casting an interface I've come up with. It's an MVP design for C# Windows Forms. I have an IView class which I implement on my form classes. There's also an IPresenter which I derive into various…
Stephen York
  • 1,247
  • 1
  • 13
  • 42
19
votes
5 answers

covariance in c#

Is it possible to cast a List to List in C# 4.0? Something along these lines: class joe : human {} List joes = GetJoes(); List humanJoes = joes; Isn't this what covariance is for? if you can do: human h = joe1…
Sonic Soul
  • 23,855
  • 37
  • 130
  • 196
19
votes
2 answers

Covariant return types, const-ness, and incomplete classes

This code compiles successfully under g++ 6.1 but gives an error with clang 3.8: class C; class Base { public: virtual const C *getC(); }; class Derived : public Base { public: virtual C *getC(); }; The error from clang is as follows: $…
Chris Morley
  • 891
  • 6
  • 16
19
votes
4 answers

Is there a way to forward declare covariance?

Suppose I have these abstract classes Foo and Bar: class Foo; class Bar; class Foo { public: virtual Bar* bar() = 0; }; class Bar { public: virtual Foo* foo() = 0; }; Suppose further that I have the derived class ConcreteFoo and ConcreteBar.…
Tobias
  • 6,388
  • 4
  • 39
  • 64
18
votes
1 answer

c# 9.0 covariant return types and interfaces

I have two code examples: One compiles class C { public virtual object Method2() => throw new NotImplementedException(); } class D : C { public override string Method2() => throw new NotImplementedException(); …
Alex Butenko
  • 3,664
  • 3
  • 35
  • 54