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 asB & A
.