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

Use super method with sub type param

I'm trying to implement some function in a super class so I don't have to always repeat it in its children. Sample: trait Animal { def applyF(transition: Animal => Animal): Animal = transition(this) // Animal as param and return type } case class…
Piu130
  • 1,288
  • 3
  • 16
  • 28
0
votes
3 answers

Can't get co/contra-variance to work in C#

abstract class A { List Items { get; set; } } class B {} class C : A {} class D : B {} class E : A {} static class X { public A GetThing(bool f) { return f ? new E() : new C(); } } Type of conditional expression cannot…
enashnash
  • 1,578
  • 1
  • 15
  • 36
0
votes
1 answer

C# How to iterate over a Dictionary of common parent class for generic children?

I have this situation: class Animal { int size; } class Dog : Animal { string Name; } class Cat : Animal { string Alias; } public void Check( Dictionary animals ) { foreach(var pet in animals){...} } My question is…
Fabio Andrés
  • 229
  • 2
  • 11
0
votes
3 answers

Misunderstanding on Contravariance in Java with code example

I am trying out a easy to understand example about contravariance in Java and having a issue understanding. In the below example I have List list1 . My understanding is i should be able to add an object of any superclass of CarBill.…
Som Bhattacharyya
  • 3,972
  • 35
  • 54
0
votes
0 answers

Why is interface covariance required in this case?

I am making a common action filter, depending on common, generic services to perform a certain task across multiple similar projects. Structure Base filter - contains the logic and accepts a service parameter in the constructor: public abstract…
Alex
  • 715
  • 1
  • 8
  • 29
0
votes
2 answers

Covariance in generic parameter and convention based on parameter type

I'm really struggling to create interface/convention based rules for FluentValidator. It has following class abstract class AbstractValidator { IRuleBuilderInitial RuleFor(Expression>…
MistyK
  • 6,055
  • 2
  • 42
  • 76
0
votes
1 answer

Unity RegisterType() Error: there is no implicit reference conversion

I have a interface: public interface IFileRetriever where THeader : IFileRow where TBody : IFileRow where TTailer : IFileRow { IRetrievedFile Retrieve(string…
AdvancingEnemy
  • 382
  • 3
  • 20
0
votes
2 answers

Scala covariance, contravariance confusion

I am a newcomer to Scala and it's really very confusion. Please help me. /** 2 * Remember! In Scala, every function that takes one argument 3 * is an instance of Function1 with signature: 4 * 5 * trait Function1[-T, +S] extends AnyRef 6…
AZ_
  • 21,688
  • 25
  • 143
  • 191
0
votes
1 answer

Implementing Co and Contra variance generic interface & its practical uses

I am trying to understand the possible use of using a variant generic interface(using both co and contra variant). Can someone please explain? I understood co and contra variance examples for interfaces individually, Co variance example public…
Suresh
  • 347
  • 2
  • 6
  • 17
0
votes
1 answer

Convert error when there should be none since class implements required interface

I have an interface as follows: public interface IPageViewModel where T : class { string ViewName { get; set; } T SelectedItem { get; set; } List ItemsList { get; set; } } Then, I have two classes: internal class TestViewModel :…
Sazu
  • 11
  • 5
0
votes
3 answers

What am I missing in Microsoft's contravariance example?

I'm trying to understand contravariance in practice. It seemed to be straightforward when I read the book, but now I seem to have stuck. I understand there's a lot of topics on contravariance and I've googled many of them, none helped me understand…
Konstantin
  • 1,150
  • 13
  • 31
0
votes
1 answer

implementing contravariance in interface in c#

i have been going through many blogs to learn about contravariance, the more i learn the more i am getting confused on this. my question is, suppose i have an interface and the implementation as following interface ICovariant { …
Lijin Durairaj
  • 4,910
  • 15
  • 52
  • 85
0
votes
1 answer

How to change param that is interface?

The library that I'm using to work with DB provides convenient interface to save/load data without casting Put(c context.Context, key *Key, src interface{}) (*Key, error) Get(c context.Context, key *Key, dst interface{}) error However, I cannot…
Stan Kurilin
  • 15,614
  • 21
  • 81
  • 132
0
votes
1 answer

Contravariance in generics java doesnt work as expected

List myNumsContra = new ArrayList(); myNumsContra.add(2.0F); myNumsContra.add(2); myNumsContra.add(2L); System.out.println(myNumsContra.get(0)); //should throw error According to the contravariance rule…
jtkSource
  • 675
  • 9
  • 21
0
votes
1 answer

Invalid Variance in val use - error: contravariant type U occurs in covariant position

I have a question about Scala variances. The code below is valid code, which passes compile. // // VALID (COMPILE PASS!) class A[+T, -U](t: T, u: U) But the code below is not valid, which use val and doesn't pass compile. // //…
ryo
  • 2,009
  • 5
  • 24
  • 44