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

Local type inference and contravariance in generic type variables

I came accross the following code: public static Set distinct( Collection list, Comparator comparator) { Set set = new TreeSet<>(comparator); set.addAll(list); return set; } This code…
fps
  • 33,623
  • 8
  • 55
  • 110
15
votes
3 answers

Casting List - covariance/contravariance problem

Given the following types: public interface IMyClass { } public class MyClass : IMyClass { } I wonder how can I convert a List to a List? I am not completely clear on the covariance/contravariance topics, but I understand that I…
user256890
  • 3,396
  • 5
  • 28
  • 45
15
votes
3 answers

Why doesn't delegate contravariance work with value types?

This snippet is not compiled in LINQPad. void Main() { (new[]{0,1,2,3}).Where(IsNull).Dump(); } static bool IsNull(object arg) { return arg == null; } The compiler's error message is: No overload for 'UserQuery.IsNull(object)' matches…
thorn0
  • 9,362
  • 3
  • 68
  • 96
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
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

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
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
13
votes
4 answers

Covariance and Contravariance in C#

I will start by saying that I am Java developer learning to program in C#. As such I do comparisons of what I know with what I am learning. I have been playing with C# generics for a few hours now, and I have been able to reproduce the same things…
Edwin Dalorzo
  • 76,803
  • 25
  • 144
  • 205
13
votes
2 answers

could someone explain the connection between type covariance/contravariance and category theory?

I am just starting to read about category theory, and would very much appreciate it if someone could explain the connection between CS contravariance/covariance and category theory. What would some example categories be (i.e. what are their…
gatoatigrado
  • 16,580
  • 18
  • 81
  • 143
12
votes
2 answers

How to check covariant and contravariant position of an element in the function?

This is a code snippet from one of the articles that I read regarding contravariance and covariance in scala. However, I fail to understand the error message thrown by the scala compiler "error: covariant type A occurs in contravariant position in…
Chaitanya
  • 3,590
  • 14
  • 33
12
votes
7 answers

Covariance and Contravariance on the same type argument

The C# spec states that an argument type cannot be both covariant and contravariant at the same time. This is apparent when creating a covariant or contravariant interface you decorate your type parameters with "out" or "in" respectively. There is…
William Edmondson
  • 3,619
  • 3
  • 32
  • 41
12
votes
3 answers

Why Liskov Substitution Principle needs the argument to be contravariant?

One of the rules that Liskov Substitution Principle imposes on method signature in derived class is: Contravariance of method arguments in the subtype. If I understood correctly, it is saying that the derived class's overridding function should…
Mac
  • 1,711
  • 3
  • 12
  • 26
12
votes
1 answer

@uncheckedVariance in Kotlin?

In his talk Compilers are Databases, Martin Odersky presents an interesting variance corner case: class Tree[-T] { def tpe: T @uncheckedVariance def withType(t: Type): Tree[Type] } T is defined to be contravariant, because it is useful to think…
fredoverflow
  • 256,549
  • 94
  • 388
  • 662
12
votes
2 answers

Covariance and Contravariance with C# Arrays

While reading a section of an article about covariance and contravariance at Wikipedia, I ran into the following, bolded sentence: First consider the array type constructor: from the type Animal we can make the type Animal[] ("array of animals").…
wjmolina
  • 2,625
  • 2
  • 26
  • 35
11
votes
1 answer

How to determine type parameter's variance?

Inspired by Real-world examples of co- and contravariance in Scala I thought a better question would be: When designing a library, are there a specific set of questions you should ask yourself when determining whether a type parameter should be…
Bradford
  • 4,143
  • 2
  • 34
  • 44