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.

494 questions
38
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
  • 4,583
  • 3
  • 40
  • 53
38
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.
  • 14,441
  • 2
  • 45
  • 57
36
votes
3 answers

How do I return a reference to something inside a RefCell without breaking encapsulation?

I have a struct that has inner mutability. use std::cell::RefCell; struct MutableInterior { hide_me: i32, vec: Vec, } struct Foo { //although not used in this particular snippet, //the motivating problem uses interior…
Drew
  • 7,637
  • 5
  • 38
  • 40
32
votes
2 answers

Why is parameter in contravariant position?

I'm trying to use a covariant type parameter inside a trait to construct a case-class like so: trait MyTrait[+T] { private case class MyClass(c: T) } compiler says: error: covariant type T occurs in contravariant position in type T of value c I…
lapislazuli
  • 506
  • 4
  • 6
32
votes
5 answers

Why is Function[-A1,...,+B] not about allowing any supertypes as parameters?

I believe one can define covariance (at least, for objects) as 'the ability to use a value of a narrower (sub) type in place of a value of some wider (super) type', and that contravariance is the exact opposite of this. Apparently, Scala functions…
bjt38
  • 463
  • 4
  • 8
29
votes
2 answers

Example of contravariance

I am thinking of the following example to illustrate why contravariance is useful. Let's consider a GUI framework with Widgets, Events, and Event Listeners. abstract class Event; class KeyEvent extends Event class MouseEvent extends Event trait…
Michael
  • 9,937
  • 10
  • 55
  • 105
28
votes
3 answers

I can only cast a contravariant delegate with "as"

I'm trying to cast a contravariant delegate but for some reason I can only do it using the "as" operator. interface MyInterface { } delegate void MyFuncType(InType input); class MyClass where T : MyInterface { public void…
rob
  • 16,110
  • 12
  • 63
  • 90
27
votes
3 answers

How would contravariance be used in Java generics?

In Java, covariance allows the API designer to specify that an instance may be generalised as a certain type or any of that type's subtypes. For example: List shapes = new ArrayList(); // where type Circle extends…
Synesso
  • 34,066
  • 32
  • 124
  • 194
27
votes
1 answer

Why covariance does not work with generic method

Assume I have interface and class: public interface ITree {} public class Tree : ITree {} As IEnumerable is covariant, the code line below is compiled successfully: IEnumerable trees = new List(); But when I put it into generic…
cuongle
  • 69,359
  • 26
  • 132
  • 196
25
votes
2 answers

What does mean?

Resharper has suggested to change from interface IModelMapper { TTo Map(TFrom input); } into interface IModelMapper So I investigate a little and ended reading this article (found through a Wikipedia article)…
mhttk
  • 1,606
  • 1
  • 15
  • 28
25
votes
4 answers

What is the difference between covariance and contra-variance in programming languages?

Can anyone explain the concept of covariance and contravariance in programming language theory?
xdevel2000
  • 19,270
  • 35
  • 120
  • 188
24
votes
2 answers

What are good reasons for choosing invariance in an API like Stream.reduce()?

Reviewing Java 8 Stream API design, I was surprised by the generic invariance on the Stream.reduce() arguments: U reduce(U identity, BiFunction accumulator, BinaryOperator combiner) A seemingly more…
Lukas Eder
  • 181,694
  • 112
  • 597
  • 1,319
23
votes
1 answer

Why wasn't TEventArgs made contravariant in the standard event pattern in the .NET ecosystem?

When learning more about the standard event model in .NET, I found that before introducing generics in C#, the method that will handle an event is represented by this delegate type: // // Summary: // Represents the method that will handle an…
Zack ISSOIR
  • 894
  • 9
  • 24
21
votes
3 answers

Why does C# (4.0) not allow co- and contravariance in generic class types?

What is the real reason for that limitation? Is it just work that had to be done? Is it conceptually hard? Is it impossible? Sure, one couldn't use the type parameters in fields, because they are allways read-write. But that can't be the answer, can…
Lars Corneliussen
  • 2,473
  • 2
  • 26
  • 34
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,165
  • 3
  • 34
  • 71
1
2
3
32 33