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

Variance in Expression>

Just a quick and short one, this time. Func is contravariant (EDIT : The Type Parameter T is). Now, I don't work with Func, but rather with Expression>, and seem to have reached a dead end. UPDATE - FULL CODE…
Sebastian Edelmeier
  • 4,095
  • 3
  • 39
  • 60
5
votes
3 answers

How to cast generic interfaces using contravariant parameters to a base type?

I'm trying to develop a generic command processor. I would like to create command handler classes implementing a given interface. I'll use inversion of control to dinamically create an instance of the appropriate class based on the type of command…
Fernando Correia
  • 21,803
  • 13
  • 83
  • 116
5
votes
2 answers

Are there statically-typed programming-languages with inheritance where method parameters are contravariant?

Theoretically it is sound to override methods of a parent in a subclass with a method where the parameters are supertypes of the parameters in the parent class, like: class T def foo(s: String) = ... class S override def foo(a: Any) =…
soc
  • 27,983
  • 20
  • 111
  • 215
5
votes
3 answers

Expression.Convert doesn't throw InvalidOperationException for invariant value type parameters?

Expression.Convert generally throws in InvalidOperationException when "No conversion operator is defined between expression.Type and type." The return type parameter of Func<> is covariant for reference types. // This works. Func a = () =>…
Steven Jeuris
  • 18,274
  • 9
  • 70
  • 161
5
votes
1 answer

How to fix this error? Invalid variance: The type parameter 'T' must be invariantly valid on

I'm having the below error message at compile time: "Invalid variance: The type parameter 'T' must be invariantly valid on 'ConsoleApplication1.IRepository.GetAll()'. 'T' is covariant." and the below is my code: class Program { static void…
The Light
  • 26,341
  • 62
  • 176
  • 258
5
votes
1 answer

Python static type hint/check mismatch between Iterable[AnyStr] vs Iterable[str] | Iterable[bytes]

I'm running into this static type hint mismatch (with Pyright): from __future__ import annotations from typing import AnyStr, Iterable def foo(i: Iterable[AnyStr]): return i def bar(i: Iterable[str] | Iterable[bytes]): return i def…
Kache
  • 15,647
  • 12
  • 51
  • 79
5
votes
2 answers

Covariance and contravariance for wildcarded types

Can you please explain why it is possible to do: import java.util.ArrayList; import java.util.List; public class Covariance { class A { } class B extends A { } class C extends A { } public void testSmth() throws…
jdevelop
  • 12,176
  • 10
  • 56
  • 112
5
votes
4 answers

Unable to hold generic interface implementations in list c#

How to make a list hold all the different implementations of generic interface? e.g public class Animal { // some Animal implementations } public class Dog : Animal { // some Dog implementations } public class Snake : Animal { // some Snake…
kartik rajan
  • 115
  • 1
  • 5
5
votes
2 answers

Why doesn't IComparable inherit from IComparable?

In most places I read that it is a good idea to inherit from both IComparable and IComparable in your classes to provide compatibility with non-generic collections. My question is why IComparable doesn't inherit from IComparable by default…
5
votes
1 answer

Java: is a Lists's generic type parameter covariant or contravariant when consuming?

I'm a little bit confused about covariance and contravariance. Do we say that in Java something is generally contravariant when we use ? super X. Now reading my book I understood the following concept: this is contravariant: method(Predicate
Bondavalli69
  • 63
  • 1
  • 7
5
votes
1 answer

Why method defined like "cons[B >: A](v: B)" accepts argument of type which is not supertype of A?

I am studying variance in scala right now, and I think I have a good understanding of contravariance. For example given trait List[-A], I know that List[Int] is a supertype of List[AnyVal]. But say that I have the following trait: trait List[+A] { …
testing
  • 2,303
  • 4
  • 20
  • 32
5
votes
2 answers

Scala: issues using functions as first class objects

I need to have a collection of generic functions, but I can't get it done in the way I like. I created a List[(Any)=>Unit] but as soon as I try to insert a function, for example a String=>Unit I get an error. How could I declare a generic function…
mariosangiorgio
  • 1,007
  • 2
  • 13
  • 26
5
votes
2 answers

Contra- and Co-variance - CLR via C#

In the CLR via c# third edition there is an example that I cant seem to make sense of: Invariant Meaning that that generic type parameter cannot be changed. I have shown only invariant generic type parameters so far in this chapter.…
Chris G
  • 469
  • 8
  • 14
5
votes
1 answer

Type parameters defining each other? class A where T1 : Foo where T2 : T1

Does class A where T1 : Foo where T2 : T1 have an actual use case? What's the difference to class A where T1 : Foo where T2 : Foo ? What does actually change? Is it the same when variance is involved?
Wes
  • 3,978
  • 4
  • 24
  • 45
5
votes
2 answers

How can compiler compute automatically co- and contravariance?

Please note this is a question about internals of compilers. I just read [1] that when introducing variance for generic types C# team was thinking whether they should automatically compute if the type is co- or contravariant. Of course this is a…
greenoldman
  • 16,895
  • 26
  • 119
  • 185