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

Covariance and contravariance on Tasks

Given the followin snippet, i quite dont understand WHY what im going to achieve is not possible: Interface: public interface IEntityRepository : IRepository { void RequeryDataBase(); IEnumerable Search(string…
lokusking
  • 7,396
  • 13
  • 38
  • 57
15
votes
2 answers

return type covariance in protocol methods

Why doesn't swift support return type covarience in methods defined in protocols? e.g class Base { } class Derived : Base { } protocol Requirement { var someVariable : Base { get } } struct MyStruct : Requirement{ let someVariable :…
salman140
  • 1,510
  • 10
  • 11
15
votes
9 answers

How do I convert from List to List in Java using generics?

In Java, how do I convert List to List using a general purpose method so that I can replace patterns like the following with a single method call: List untypedList = new ArrayList(); // or returned from a legacy method List typedList…
Derek Mahar
  • 27,608
  • 43
  • 124
  • 174
15
votes
2 answers

Self-referential Generic Types

Consider this example: public final class Main> { public static void main(String[] args) { Main main = new Main<>(); } } This compiles perfectly. However when I try to make this compile without using the…
Paul Boddington
  • 37,127
  • 10
  • 65
  • 116
15
votes
4 answers

ref and out parameters in C# and cannot be marked as variant

What does the statement mean? From here ref and out parameters in C# and cannot be marked as variant. 1) Does it mean that the following can not be done. public class SomeClass: IVariant { public virtual R DoSomething( ref A args…
Water Cooler v2
  • 32,724
  • 54
  • 166
  • 336
15
votes
1 answer

Why does ToList not work for value types?

If I implement an interface for a value type and try to cast it to a List of it's interface type, why does this result in an error whereas the reference type converts just fine? This is the error: Cannot convert instance argument type …
Marwie
  • 3,177
  • 3
  • 28
  • 49
15
votes
1 answer

Why can't I use covariance with two generic type parameters?

Consider the following example: class Base {} class Derived : Base {} class Test1 { private List m_X; public IEnumerable GetEnumerable() { return m_X; } } This compiles just fine, because IEnumerable is…
Vincent van der Weele
  • 12,927
  • 1
  • 33
  • 61
15
votes
1 answer

Understanding scala's _ vs Any/Nothing

If a class has a convariant type parameter such as Iterable[+A], is there any difference between declaring def foo(bar: Iterable[_]) and def foo(bar: Iterable[Any]) ? If a class has a contravariant type parameter such as Growable[-A], is there…
Petr
  • 62,528
  • 13
  • 153
  • 317
15
votes
2 answers

Why classes that implement variant interfaces remain invariant?

C# 4.0 has extended the co and contravariance further for generic types and interfaces. Some interfaces (like IEnumerable) are covariants, so I can do things like: IEnumerable ie = new List(); but what about this line? I got a…
Tomas Ramirez Sarduy
  • 17,294
  • 8
  • 69
  • 85
14
votes
3 answers

Why can't I assign List to IEnumerable in .NET 4.0
I try to do this: IEnumerable ids = new List() { "0001", "0002", "0003" }; it works great! But when I try to do this: IEnumerable intIds = new List() { 1, 2, 3 }; Visual Studio tells me: Cannot implicitly…
OnlyMahesh
  • 353
  • 6
  • 18
14
votes
2 answers

Autofac: Hiding multiple contravariant implementations behind one composite

I was triggered by this SO question about (.NET 4.0) covariance and contravariance support for Autofac, and now I'm trying to achieve something similar, but without any luck. What I am trying to achieve is configure Autofac in such way that when I…
Steven
  • 166,672
  • 24
  • 332
  • 435
14
votes
3 answers

F# and interface covariance: what to do? (specifically seq<> aka IEnumerable<>)

I'm trying to call a .NET method accepting a generic IEnumerable from F# using a seq such that U is a subclass of T. This doesn't work the way I expected it would: With the following simple printer: let printEm (os: seq) = for o in…
Eamon Nerbonne
  • 47,023
  • 20
  • 101
  • 166
14
votes
2 answers

How does Optional covariance work in Swift

How does covariance work for Optionals in Swift? Say I write the following code: var nativeOptionalView: Optional let button = UIButton() nativeOptionalView = .Some(button) var nativeOptionalButton = Optional.Some(button) nativeOptionalView…
fpg1503
  • 7,492
  • 6
  • 29
  • 49
14
votes
3 answers

Build failure in unit test project with accessors of a project containing covariant types

I added a covariant interface to our project: interface IView { } interface IPresenter where TView : IView { TView View { get; } } I created some classes, implementing these interfaces: class TestView : IView { } class…
Enyra
  • 17,542
  • 12
  • 35
  • 44
14
votes
3 answers

Contravariance vs Covariance in Scala

I just learned Scala. Now I am confused about Contravariance and Covariance. From this page, I learned something below: Covariance Perhaps the most obvious feature of subtyping is the ability to replace a value of a wider type with a value of a…
CSnerd
  • 2,129
  • 8
  • 22
  • 45