Variances in Scala
Tags: scala, java, jvm, functional
Published: 2020-08-10 12:41:48

[Scala ](https://www.scala-lang.org/)supports using type parameters to implement a classes and functions that can support multiple types. Type parameters are very useful when creating a [generics](https://docs.scala-lang.org/tour/generic-classes.html). However, advanced use cases may require you to specify a constraints on types used. That’s where a Variances help to model the relationships between generic types. This post will cover the topic of type variances in Scala.

## What is Variance?
>  *Variance is the correlation of subtyping relationships of complex types and the subtyping relationships of their component types.*
>  [Scala-lang.org](https://docs.scala-lang.org/tour/variances.html)

In other words, variance allows developers to model the relationships between types and component types. As a consequence, variance allows to create a clean and very usable generic classes that are widely used in various Scala libraries.

Scala supports thee types of variance: **covariance**, **invariance** and **contravariance**. With this in mind, let’s look at each of these in greater detail.

## Covariance

Let’s assume that we have the following class structure
```
    abstract class Vehicle {
      def name: String
    }
    case class Car(name: String) extends Vehicle
    case class Bus(name: String) extends Vehicle

    class VehicleList[T](val vehicle: T)
```
The `Car` and `Bus` classes both inherit from abstract class `Vehicle`. Considering that class Car has its own collection `VehicleList[Car]`: is `VehicleList[Car]` a subtype of `VehicleList[Vehicle]`? The answer is no. Despite the fact that `Car` class extends a `Vehicle` class, the same can't be said about `VehicleList[Car]` and `VehicleList[Vehicle]`.
```
    val vehicleList: VehicleList[Vehicle] = new VehicleList[Car](new Car("bmw")) // incorrect: type mismatch
```
The solution to this is to use a **covariance**. As a consequence, a `VehicleList[Car]` will be a subtype of `VehicleList[Vehicle]`. This allows for greater polymorphism with generic types. To make `VehicleList` class `T` parameter covariant, just add a little + sign along the type:
```
    class VehicleList[+T](val vehicle: T)

    val vehicleList: VehicleList[Vehicle] = new VehicleList[Car](new Car("bmw")) // correct
```
## Contravariance

In contrast to covariance, contravariance allows the generic type `T` to be `T` or a supertype of `T`. For instance, let's consider the example class, similar to one used above:
```
    class CarList[T](val car: T)
```
The `CarList` class expects to get type parameter `T` and no other super or sub type. What if we want to use the `CarList[Car]` class to store the Vehicle class instances as well?
```
    val carList: CarList[Car] = new CarList[Vehicle](new Vehicle("boat")) // incorrect: type mismatch
```
To address that, instead of a + sign in the type definition, use the - sign.
```
    class CarList[-T](val car: T)

    val carList: CarList[Car] = new CarList[Vehicle](new Vehicle("boat")) // correct
```
## Invariance

Invariance is the default relationship of generic type `T`. The `List[Car]` accepts only `Car` type - any super type or sub type is not accepted.
```
    class List[T](val t: T)
```
## Summary

To summarize, Scala and variance system is a very handy tool to model relationships between generics types. I hope this post helped you to understand this better, so you can start using it right away!

{% twitter 1256563064134041600 %}