Union and Intersection Types in Scala 3
Scala 3 aka dotty comes with a lot of new types. Union, Intersection , Opaque etc. Let’s understand union and intersection types in detail.
Union types
A union type A | B
represents a type that has values of type A
or B
at a given time. A pattern match must be performed at the point of usage to extract the exact type.
This would not have been possible in Scala 2. We would have to create a super type for our types and then create the method with the super type.
Rules for Union types
- Union types are commutative i.e
A | B
is same asB | A
. A
andB
are sub types ofA | B
for all values ofA
andB
- Co- Variance rules for Union types : Given a co-variant type
C
thenC[A] | C[B] <: C[A | B]
Basically we can pass a List[Int]
and a List[String]
to a method expecting a List[Int|String]
. This makes C[A]
and C[B]
a sub type of C[A|B]
.
Also we can pass List[String]|List[Int]
type where a List[String|Int]
is expected. This makes C[A] | C[B]
a sub type of C[A|B]
. However the reverse is not possible as seen in line 24.
- Contra-variance rules for Union types : Given a contra variant type C then
C[A | B] <: C[A]
andC[A | B] <: C[B]
Here, we see that we could pass a Printer[String|Int]
where a Printer[Int]
was required.
Intersection types
A intersection type A & B
represents a type that has values of type A
andB
at the same time.
At line 8 we are able to use both methods from intersection type i.e monoid
contains the functionality of both Semigroup and Indentity types. The intersection type will also act as a type restriction, so we need to mix in both traits if we are to use this method properly.
Rules for Intersection types
- Intersection types are commutative i.e
A & B
is same asB & A
. - Given any types
A
andB
,A & B
is a sub type for bothA
andB
- Co- Variance rules for Intersection types : Given a co-variant type
C
thenC[A & B] <: C[A] & C[B]
Here, we see that we can provide an Option[TwitterPost & InstagramPost]
when we need a Option[TwitterPost]
or a Option[InstagramPost]
. This also leads us to the fact that when we need an Option[TwitterPost] & Option[InstagramPost]
we can provide a Option[TwitterPost & InstagramPost]
.
- Given a contra-variant type
C
aC[A |B]
is a sub type ofC[A] & C[B]
What happens here is that a Printer
instance which knows how to print Int|String
can be passed when we need a Printer[Int] & Printer[String]
. This is exactly what is done is line 15.
- what happens the two intersected types share a method signature except the returned types?
Here both Singer
and Dancer
types have a method called share
with the same signature but different return types. An intersection type of these two upon calling the share
method must return both an InstagramPost
and a TwitterPost
. The only type that can do that is an intersection i.e TwitterPost & InstagramPost
.
Conclusion
We explored Union and Intersection types in Scala 3 and checked how these types work with variance rules in Scala. Checkout the official dotty docs for further reading