## 1. Overview

In this tutorial, we will be looking at Scala variances. **Variance tells us if a type constructor** (equivalent to a generic type in Java) **is a subtype of another type constructor**.

We’ll also take a look at the three main types of variance – invariance, covariance, and contravariance – and how they differ.

## 2. Subtyping and Type Constructors

Every programming language supports the concept of types. **Types give information to a program about how to handle values at runtime**. Subtyping adds more constraints to the values of a type.

For simple types, the story is straightforward:

```
sealed trait Test
class UnitTest extends Test
class IntegrationTest extends UnitTest
class FunctionalTest extends IntegrationTest
```

The type *FunctionalTest* is a subtype of *IntegrationTest*, which is a subtype of the class *UnitTest.*

Additionally, many programming languages also support generic types or type constructors. **Type constructors are a mechanism that creates new types starting from old ones**. They provide type variables that we can bind to concrete types.

Let’s say that we want to model the result of a test on an object of type generic type *T*. We can use a type constructor to model such a situation:

```
class TestResult[T](id: String, target: T) {
// Class behavior
}
```

**Variance defines the subtyping relationship among type constructors,** using the subtyping relationship among the types that bind their type variables. In other words, for a type constructor *F[_]*, if *B* is a subtype of *A*, variance describes the relationship between the type *F[B]* and the type *F[A].*

## 3. Variances

There are three types of variance: covariance, contravariance, and invariance. Let’s look at each of them in detail.

### 3.1. Covariance

Covariance is a concept that is very straightforward to understand. We say that a type constructor *F[_] *is covariant if *B* is a subtype of type *A* and *F[B]* is a subtype of type *F[A]*. In Scala, we declare a covariant type constructor using the notation *F[+T]*, adding a plus sign on the left of the type variable.

Consider our *Test* type hierarchy from the previous section. We are assuming the type *UnitTest *is at the base of the hierarchy, and that at each step, we are adding more sophisticated and evolved features. Often, we need to execute tests in a suite, and not only in isolation. A test suite is nothing more than a list of tests:

`class TestsSuite[+T](tests: List[T])`

We defined the type constructor *TestsSuite* as covariant, which means that the type *TestsSuite[IntegrationTest]* is a subtype of *TestsSuite[UnitTest]*. The covariance property allows us to declare a variable like:

`val suite: TestsSuite[Test] = new TestsSuite[UnitTest](List(new UnitTest))`

Every time we need to assign a variable of type *TestsSuite[T]*, we can use an object of type *TestsSuite[R]*, given that *R *is a subtype of *T*. In this case, **covariance is type-safe because it reflects the standard behavior of subtyping**. Assigning an object to a variable of one of its supertypes is always safe.

If we remove the covariant annotation from the type constructor *TestsSuite[T]*, the compiler warns us that we cannot use an object of type *UnitTest *in the above example:

```
type mismatch;
found : com.baeldung.scala.variance.Variance.TestsSuits[com.baeldung.scala.variance.Variance.UnitTest]
required: com.baeldung.scala.variance.Variance.TestsSuits[com.baeldung.scala.variance.Variance.Test]
Note: com.baeldung.scala.variance.Variance.UnitTest <: com.baeldung.scala.variance.Variance.Test, but class TestsSuits is invariant in type T.
You may wish to define T as +T instead. (SLS 4.5)
val suite: TestsSuits[Test] = new TestsSuits[UnitTest](List(unitTest))
^
```

There are many examples in the Scala SDK of type constructors declared as covariant concerning their type variable. The more popular are *List[T]*, *Option[T]*, and *Try[T]*, to name a few.

### 3.2. Contravariance

We say that a type constructor *F[_] *is contravariant if *B* is a subtype of type *A* and *F[A]* is a subtype of type *F[B]*. This relation is **precisely the contrary of the covariance relation**. In Scala, we declare a contravariant type constructor using the notation *F[-T]*, adding a minus sign on the left of the type variable.

At first sight, contravariance may seem counterintuitive. Why do we need to have this type of relationship for type constructors? Let’s define a hierarchy of classes, modeling an employee’s domain model:

```
class Person(val name: String)
class Employee(name: String, val salary: Int) extends Person(name)
class Manager(name: String, salary: Int, val manages: List[Employee]) extends Employee(name, salary)
```

We can define a type constructor that represents a test assertion:

```
class Assert[-T](expr: T => Boolean) {
def assert(target: T): Boolean = expr(target)
}
```

An instance of type *Assert* is a function from a generic type *T* to *Boolean*. It should verify that some property holds an object of type *T, *called *target.
*

A list of *Assert* on the employee hierarchy verifies conditions on the attributes of the classes:

```
val personAssert = new Assert[Person](p => p.name == "Alice")
val employeeAssert = new Assert[Employee](e => e.name == "Bob" && e.salary)
val managerAssert = new Assert[Manager](m => m.manages.nonEmpty)
```

It is feasible that we want to test more than one *Assert* on the same target object. We can define an aggregate type *Asserts*:

```
trait Asserts[T] {
def asserts: List[Assert[T]]
def execute(target: T): Boolean =
asserts
.map(a => a.assert(target))
.reduce(_ && _)
}
```

The type constructor *Asserts* is a list of *Assert* that we want to *execute* on the same *target* object. We can specialize *Asserts* on the *Employee* type, obtaining a list of *Assert* that we can run on an *Employee* instance:

`class AssertsEmployee(val asserts: List[Assert[Employee]]) extends Asserts[Employee]`

What kind *Assert* can we test on an *Employee*? The type constructor *Assert* is defined as a contravariant, which means that *Assert[Person]* is indeed a subtype of *Assert[Employee]*. Therefore, the list of *Assert* can contain instances of either *Assert[Employee]* or *Assert[Person]*:

```
val bob = new Employee("Bob", 50000)
val tester = new AssertsEmployee(List(personAssert, employeeAssert))
tester.execute(bob)
```

We can execute an *Assert[Empoyee]* on an object of type *Employee, *testing the attribute *name* and the attribute *salary*. We can also run an *Assert[Person]* on an object of type *Employee*. In this case, an assert can test only the property *name* that an *Employee* owns.

If we try to remove the contravariance annotation from the definition of the *Assert* type constructor, the compiler warns us that we are missing something:

```
type mismatch;
found : com.baeldung.scala.variance.Variance.Assert[com.baeldung.scala.variance.Variance.Person]
required: com.baeldung.scala.variance.Variance.Assert[com.baeldung.scala.variance.Variance.Employee]
Note: com.baeldung.scala.variance.Variance.Person >: com.baeldung.scala.variance.Variance.Employee, but class Assert is invariant in type T.
You may wish to define T as -T instead. (SLS 4.5)
val tester = new AssertsEmployee(List(personAssert, employeeAssert))
^
```

What about the type *Assert[Manager]*? An assert on a manager could test the attribute *manages* that an object of type *Employee* does not have:

```
val tester = new AssertsEmployee(List(managerAssert))
tester.execute(bob)
```

Therefore, the compiler warns us that we cannot use an object of type *Assert[Manager]*:

```
type mismatch;
found : com.baeldung.scala.variance.Variance.Assert[com.baeldung.scala.variance.Variance.Manager]
required: com.baeldung.scala.variance.Variance.Assert[com.baeldung.scala.variance.Variance.Employee]
val tester = new AssertsEmployee(List(managerAssert))
^
```

In the Scala SDK, the most popular contravariant type constructor is *Function1[-T1, +R]. *The type constructor represents a function with one parameter of type *T1*. As we have already seen, **when we use a type variable as an input parameter to a function or a method, contravariance comes to the rescue, allowing us to define type-safe code**.

### 3.3. Invariance

The third type of relationship between a type constructor and its type variables is invariance. We say that a type constructor *F[_] *is invariant if any subtype relationship between types *A* and *B* is not preserved in any order between types *F[A] *and *F[B].*

If we remove the contravariance property (-) from the previous *Assert *type, we obtain an invariant type constructor:

```
class Assert[T](expr: T => Boolean) {
def assert(target: T): Boolean = expr(target)
}
```

Let’s try to assign a variable of type *Assert[Person] *to an object of type *Assert[Employee]*:

`val personAssert: Assert[Person] = new Assert[Employee](p => p.name == "Alice")`

Due to the invariance on *T, *the compiler warns us correctly:

```
type mismatch;
found : com.baeldung.scala.variance.Variance.Assert[com.baeldung.scala.variance.Variance.Employee]
required: com.baeldung.scala.variance.Variance.Assert[com.baeldung.scala.variance.Variance.Person]
Note: com.baeldung.scala.variance.Variance.Employee <: com.baeldung.scala.variance.Variance.Person, but class Assert is invariant in type T.
You may wish to define T as +T instead. (SLS 4.5)
val personAssert: Assert[Person] = new Assert[Employee](p => p.name == "Alice")
^
```

Invariance is the only type of relationship available in many programming languages that allows the use of type constructors, similar to Java and C++.

## 4. Conclusion

In this article, we introduced the concept of type constructors or generic types. Starting from the notion of subtyping defined for simple types, we showed how the subtype concept translates to type constructors through the definition of variance.

We looked at the three types of variance: covariance, contravariance, and invariance. We concluded that if we use a generic type variable assignment, we need to use covariance, and if we use a generic type as an argument, we need to use contravariance.

As always, the code from this article can be found over on GitHub.