Questions tagged [contravariance]

Within the type system of a programming language, covariance and contravariance refers to the ordering of types from narrower to wider and their interchangeability or equivalence in certain situations (such as parameters, generics, and return types)

Within the type system of a programming language, a typing rule or a type conversion operator is:

covariant if it preserves the ordering, ≤, of types, which orders types from more specific to more generic;

contravariant if it reverses this ordering, which orders types from more generic to more specific;

invariant if neither of these applies.

These terms come from category theory, which has a general definition of covariance and contravariance that unifies the computer science definition of these terms with the definition used in vector spaces.

This distinction is important in considering argument and return types of methods in class hierarchies. In object-oriented languages such as Python, if class B is a subtype of class A, then all member functions of B must return the same or narrower set of types as A; the return type is said to be covariant. On the other hand, if the member functions of B take the same or broader set of arguments compared with the member functions of A, the argument type is said to be contravariant. The problem for instances of B is how to be perfectly substitutable for instances of A. The only way to guarantee type safety and substitutability is to be equally or more liberal than A on inputs, and to be equally or more strict than A on outputs. Note that not all programming languages guarantee both properties in every context, and that some are unnecessarily strict; they are said not to support covariance or contravariance in a given context; the behavior of some programming languages is discussed below.

Typical examples:

The operator which constructs array types from element types is usually covariant on the base type: since String ≤ Object then ArrayOf(String) ≤ ArrayOf(Object). Note that this is only correct (i.e. type safe) if the array is immutable; if insert and remove operators are permitted, then the insert operator is covariant (e.g. one can insert a String into an ArrayOf(Object)) and the remove operator is contravariant (e.g. one can remove an Object from an ArrayOf(String)). Since the mutators have conflicting variance, mutable arrays should be invariant on the base type.

Let f be a function with a parameter of type T and let g be a function with a parameter of type S, both with the same return type. If T ≤ S, then g ≤ f. g can replace f anywhere, since it cares less about the type of its parameter, and both return the same type. Because the subtype relation between the argument type and the functions is reversed, the function type is said to be contravariant on its argument type.

Let f be a function that returns a value of type T and let g be a function that returns a value of type S, both with the same parameter type. If T ≤ S, then f ≤ g. f can replace g anywhere, since it returns only a subset of all possible values returned by g, and both take the same argument. Because the subtype relation between the argument type and the functions is preserved, the function type is said to be covariant on its return type.

In object-oriented programming, substitution is also implicitly invoked by overriding methods in subclasses: the new method can be used where the old method was invoked in the original code. Programming languages vary widely on their allowed forms of overriding, and on the variance of overridden methods' types.

540 questions
5
votes
1 answer

Method inheritance on contravariant type

I have defined two typeclasses: trait WeakOrder[-X] { self => def cmp(x: X, y: X): Int def max[Y <: X](x: Y, y: Y): Y = if (cmp(x, y) >= 0) x else y def min[Y <: X](x: Y, y: Y): Y = if (cmp(x, y) <= 0) x else y } trait Lattice[X] { self => …
Tongfei Chen
  • 613
  • 4
  • 14
5
votes
2 answers

Does C# 4's covariance support nesting of generics?

I don't understand why 'x' below converts, but 'y' and 'z' do not. var list = new List>(); IEnumerable> x = list; List> y = list; IEnumerable> z = list; Does the new covariance feature simply…
scobi
  • 14,252
  • 13
  • 80
  • 114
5
votes
3 answers

what does List mean?

I saw that definition in a protobuf generated java file: java.util.List foo(); But what dose I can't understand List
Sayakiss
  • 6,878
  • 8
  • 61
  • 107
5
votes
2 answers

Java snippet that causes stack overflow in the compiler or typechecker (javac)?

Yesterday at a seminar the presenter (Peter Sestoft) showed a small java program, with 3 classes, featuring both co-variance and contra-variance. When attempting to compile using javac, the type checker will throw a StackOverflowException. The…
5
votes
1 answer

IsAssignableFrom in covariance and contravariance

How can I detect if type x is assignable from type y not only through inheritance hierarchy but also through covariance and contravariance?
Alwyn
  • 8,079
  • 12
  • 59
  • 107
4
votes
3 answers

Passing a variable number of generic type parameters

to be specific, I want to write an export function which I can use like this: List HistoryBooks = something; List MathBooks = something; List ScienceBooks = something; ExcelExporter.Export(FileName, HistoryBooks,…
Jens
  • 505
  • 5
  • 17
4
votes
2 answers

Override contra-variance workaround needed

I'm having difficulty finding the (what I'm sure is a very common) design pattern to work around the following problem. Consider this piece of code: class AA {}; class BB : public AA {}; class A { public: virtual void foo(AA& aa) = 0; }; class…
eladidan
  • 2,634
  • 2
  • 26
  • 39
4
votes
0 answers

Understanding Generic Invariance, Covariance and Contravariance

Variance in generics is something that has always confused me. The following rules are what I was led to believe: Invariant T: Only accepts types of T; nothing more, nothing less. Covariant T: Accepts types of T and types derived from T, but no…
Matthew Layton
  • 39,871
  • 52
  • 185
  • 313
4
votes
1 answer

What does 'contravariance' on AbstractRecoilValue mean in Recoil source type declarations?

I stumbled upon this part of typescript/index.d.ts in Recoil source: export class AbstractRecoilValue { __tag: [T]; __cTag: (t: T) => void; // for contravariance key: NodeKey; constructor(newKey: NodeKey); } How does __cTag…
tondi
  • 53
  • 6
4
votes
2 answers

Use-site vs declaration-site difference in type projections in Kotlin

Type Hierarchy open class Fruit() open class CitrusFruit : Fruit() class Orange : CitrusFruit() Declaration-site Variance The Crate is used as a producer or consumer of Fruits. Invariant class class Crate(private val elements: MutableList)…
Yogesh Umesh Vaity
  • 41,009
  • 21
  • 145
  • 105
4
votes
2 answers

C# dont understand covariance and contravariance of delegates

For a long time now I have been trying to understand the usefulness of the "in" and "out" parameters in connection with generics in C # and I just can't get it into my head(I know how often this question is asked on StackOverflow). I generally…
Coco07
  • 43
  • 5
4
votes
2 answers

Scala: passing a contravariant type as an implicit parameter does not choose the nearest supertype?

Why does the following code does not pick up the implicit val with the nearest supertype? class A class B extends A trait TC[-T] { def show(t: T): String } implicit val showA = new TC[A] { def show(a: A): String = "it's A" } implicit val showB =…
cubic lettuce
  • 6,301
  • 3
  • 18
  • 25
4
votes
2 answers

Covariance and contravariance in C++ function pointer?

Consider this class Base { }; class Derived : public Base { }; Base *f1(Derived *) { return {}; } Derived *f2(Derived *) { return {}; } // covariant Base *f3(Base *) { return {}; } // contravariant Derived *f4(Base *) { return {}; } // covariant…
vbstb
  • 1,261
  • 1
  • 10
  • 14
4
votes
1 answer

Why isn't a vector of smart pointers to an item implementing an interface covariant with that interface?

Why isn't a vector of smart pointers covariant with an interface that item implements? e.g. if I have a vector of pointers to a dog, why can't I use that as a vector of pointers to iAnimal? #include #include #include…
Carbon
  • 3,828
  • 3
  • 24
  • 51
4
votes
3 answers

Interface covariance contravariance : why is this not compiling?

I want to implement a CommandBus that can Dispatch some Commands to CommandHandlers. A Command is a simple a DTO describing what should happen. For instance : "Increment counter by 5" A CommandHandler is able to handle a precise type of…