## Co and Contravariance in .NET and Java – Part I – Type Relations

For my university courses I am learning Java at the moment, something that I have always wanted to do to broaden my horizon but also for getting some exposure to the platform that, together with .NET, features the largest market share. In a previous blog post I did a comparison of the different generics implementation in Java and the .NET framework, and now that I will be using Java a lot more often I think its the right moment to extend this comparison on Covariance and Contravariance.

This subject has been covered in great detail on the net, and I can wholeheartedly recommend Eric Lipperts and Bart de Smet’s Blog posts on the subject, which is also where I’ll reference some of the material for this postis from.

## Type System Terminology

In any Object-Oriented type system the type relation of two objects A and B can be characterized in exactly one of the following ways:

- A has the same type as B
- A is a subtype of B
- B is a subtype of A
- A and B are not related.

We can establish a well defined ordering relation between two types as* “X is assignment compatible to Y”, written as X <: Y. *Assignment compatible means that an instance of X can be used instead of an instance of Y everywhere where Y is applicable. The easisest example of X <: Y would be string <: object, but there’s also float<: double (a float is narrower than a double, with respect to the range of values it can represent) . Assignment compatibility establishes a partial order relationship,

**because it fulfils the three necessary properties:**

- (reflexivity) For all types T:
*T<: T* - (antisymmetry) For all types T and U:
*T <: U and U <: T implies U = T* - (transitivity) For all types S, T and U:
*S <: U and U <: T implies S <: T*

To give an example of what this means, is that given a related set of types (a linear inheritance hierachy), <: will order them from more specific to more generic ones, e.g *Car <: Vehicle <: Object*. As we’ll see later in this series, having a formal notion for type relations will help us formally understand the concept of Covariance and Contravariance.

The next concept I want to introduce is that of a ** type operation**. Analogous to the mathematical definition of an operation, a type operation has the signature T -> U where T and U are types. An example for a common type transformation is a type cast. A cast to the common root class

*Object*would be defined as c : { Type -> Type; T -> Object}. For the mathematically inclined, note that

*Object*is the maximum in our set of Types regarding the relation

*<:*, because for all types

*T, T <: Object.*

The probably most interesting set of type operations is what Haskell calls a** Type Constructor**. Whenever you are using a constructed type (such as a generic type or an array) you are using a type constructor (not in the CLR sense where this refers to a static cctor.) IEnumerable is one of the types you’d use with such a constructor, which has the signature T -> IEnumerable. So whenever you are using a generic instantiation (a generic type with concrete Type arguments), you have effectively used a type operation.

In the next post, we’ll discuss some common type operations and define what covariance and contravariance means.