Bartosz Witkowski - Blog.

Variance (wikipedia, scala-lang) is a thing that seems trivial on the first glance but is a useful tool for guaranteeing type safety. It took me a while to grok all of its implications, and I’ll summarize variance and the “so what?” behind it.

# Variance

In scala generic parameters of classes can be annotated with additional variance annotations. Those annotations impose further bounds on how the declared class can be used.

Variance is somewhat akin to the Liskov Substitution Principle. LSP states that subclasses should be used transparently in place of their superclasses.

Variances imposes some additional limitations on how we can correctly use a generic class in terms of sub- and super- typing.

## Covariance

An example of a covariant class in scala is the immutable `Vector`.

Consider this class hierarchy which we will use for the examples:

Covariance defines the following relationship: if `A` is a subtype of `B` then `Vector[A]` is a subtype of `Vector[B]`. Concretely `Vector[Dog]` is a subtype of `Vector[Animal]`.

Another way of looking at it is if a Vector is covariant we must be able to use `Vector[Dog]` in any place that we would use `Vector[Animal]` because `Animal` is of type `Dog` or wider. Covariance implies a conversion between a narrower type and a wider type - you may treat `Vector[Dog]` as if it’s `Vector[Animal]`.

## Invariance

If a class parameter is invariant it means that no conversion wider to narrower, nor narrower to wider may be performed on the class.

The most common usage of invariance are mutable collections. An `Array` is an example of an invariant class.

Invariance is important for type safety of mutable collections. Java, famously, has covariant mutable arrays. This should show you why it’s a bad idea:

Because of this users of arrays in can be fooled into thinking they are dealing with `Object[]` instead `String[]`. If java would allow storing `Integer`s into a `String` array this would blow up at the read site - the “readers” of the array would think they are still dealing with a `String` array but and not a `Object` array and try to read strings from it.

## Contravariance

Contravariance is in some way the polar opposite of covariance. The canonical example of a contrvariant class in scala is `Function1[-T1, +R]`. Why does `Function1` need to be contrvariant on its the input parameter?

Let’s think in term of conversions. Covariance, which was discused before, implies that there exists a conversion between `Vector[Dog]` to `Vector[Animal]` because `Dog` is a subclass of `Animal`. Does a similar conversion make sense in the case of `Function1`?

If we have `Function1[Dog, Any]` then in the general case this function should work for `Dog`s and its subtypes. But not necessarily for animals because it may use “features” (methods) that are only available to the subtype.

The reverse conversion works however - if we have a function that works on `Animals` then this function by design should work on `Dogs`.

Contravariance means that if `B` is a supertype of `A` then `Function1[A, R]` is a supertype of `Function1[B, R]`. Concretely `Function1[Dog, Any]` is a supertype of `Function1[Animal, Any]`.

# Variance and type safety

When defining a generic class with a `var` field we can get compile time errors:

Let’s break it down a little. Why doesn’t the compiler allow getters in the `Covariant` class?

Why? Let’s think about usages of covariance let’s say that we have a class:

If the `print` method can print `Dog`s does it make sense (in general) that it should also print `Animals`? Maybe sometimes but in the general sense if we want to generalize the `Printer` class we should use contravariance. The compiler is smart enough to check this type of usage for us.

Let’s think about the second use case: returning a generic parameter:

And again - does it make sense that `Create` should generalize by contravariance? If `Create` returns instances of the `Animal` class should we be able to use it in every place that expects `Create[Dog]`? The scala compiler is smart enough that it explodes in our face if we try it.

# Edit history

## 2013-10-21

• Spelling errors.
• Fixed an error in the description of contravariance. Thanks tmk!