Home > .NET vs. Java > Co and Contravariance in .NET and Java – Part I – Type Relations

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.

Categories: .NET vs. Java
  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: