Scala 3 — Book

Intersection Types

Language
This doc page is specific to Scala 3, and may cover new concepts not available in Scala 2. Unless otherwise stated, all the code examples in this page assume you are using Scala 3.

Used on types, the & operator creates a so called intersection type. The type A & B represents values that are both of the type A and of the type B at the same time. For instance, the following example uses the intersection type Resettable & Growable[String]:

trait Resettable:
  def reset(): Unit

trait Growable[A]:
  def add(a: A): Unit

def f(x: Resettable & Growable[String]): Unit =
  x.reset()
  x.add("first")

In the method f in this example, the parameter x is required to be both a Resettable and a Growable[String].

The members of an intersection type A & B are all the members of A and all the members of B. Therefore, as shown, Resettable & Growable[String] has member methods reset and add.

Intersection types can be useful to describe requirements structurally. That is, in our example f, we directly express that we are happy with any value for x as long as it’s a subtype of both Resettable and Growable. We did not have to create a nominal helper trait like the following:

trait Both[A] extends Resettable with Growable[A]
def f(x: Both[String]): Unit
trait Both[A] extends Resettable, Growable[A]
def f(x: Both[String]): Unit

There is an important difference between the two alternatives of defining f: While both allow f to be called with instances of Both, only the former allows passing instances that are subtypes of Resettable and Growable[String], but not of Both[String].

Note that & is commutative: A & B is the same type as B & A.

Contributors to this page: