|
| 1 | +--- |
| 2 | +layout: doc-page |
| 3 | +title: "Intersection Types - More Details" |
| 4 | +--- |
| 5 | + |
| 6 | +## Syntax |
| 7 | + |
| 8 | +Syntactically, an intersection type is similar to an infix type, |
| 9 | +where the infix operator is `&`. |
| 10 | + |
| 11 | +``` |
| 12 | +Type ::= ...| InfixType |
| 13 | +InfixType ::= RefinedType {id [nl] RefinedType} |
| 14 | +RefinedType ::= WithType {[nl] Refinement} |
| 15 | +WithType ::= AnnotType {‘with’ AnnotType} |
| 16 | +``` |
| 17 | + |
| 18 | +## Type Checking |
| 19 | + |
| 20 | +The type `S & T` represents values that are of the type `S` and `T` at the same time. |
| 21 | + |
| 22 | +```scala |
| 23 | +trait Resettable { |
| 24 | + def reset(): this.type |
| 25 | +} |
| 26 | +trait Growable[T] { |
| 27 | + def add(x: T): this.type |
| 28 | +} |
| 29 | +def f(x: Resettable & Growable[String]) = { |
| 30 | + x.reset() |
| 31 | + x.add("first") |
| 32 | +} |
| 33 | +``` |
| 34 | + |
| 35 | +The value `x` is required to be _both_ a `Resettable` and a |
| 36 | +`Growable[String]`. |
| 37 | + |
| 38 | +The members of an intersection type `A & B` are all the members of `A` and all |
| 39 | +the members of `B`. For instance `Resettable & Growable[String]` |
| 40 | +has member methods `reset` and `add`. |
| 41 | + |
| 42 | +If a member appears in both `A` and `B`, its type in `A & B` is the intersection |
| 43 | +of its type in `A` and its type in `B`. For instance, assume the definitions: |
| 44 | + |
| 45 | +```scala |
| 46 | +trait A { |
| 47 | + def children: List[A] |
| 48 | +} |
| 49 | +trait B { |
| 50 | + def children: List[B] |
| 51 | +} |
| 52 | +val x: A & B = new C |
| 53 | +val ys: List[A & B] = x.children |
| 54 | +``` |
| 55 | + |
| 56 | +The type of `children` in `A & B` is the intersection of `children`'s |
| 57 | +type in `A` and its type in `B`, which is `List[A] & List[B]`. This |
| 58 | +can be further simplified to `List[A & B]` because `List` is |
| 59 | +covariant. |
| 60 | + |
| 61 | +An intersection type `A & B` may not be inhabited, e.g. `Int & String` is not inhabited. |
| 62 | +`A & B` is just a type that represents a set of requirements for |
| 63 | +values of the type. At the point where a value is _constructed_, one |
| 64 | +must make sure that all inherited members are correctly defined. |
| 65 | +So if one defines a class `C` that inherits `A` and `B`, one needs |
| 66 | +to give at that point a definition of a `children` method with the required type. |
| 67 | + |
| 68 | +```scala |
| 69 | +class C extends A with B { |
| 70 | + def children: List[A & B] = ??? |
| 71 | +} |
| 72 | +``` |
| 73 | + |
| 74 | +## Subtyping Rules |
| 75 | + |
| 76 | +``` |
| 77 | + T <: A T <: B |
| 78 | + ---------------- |
| 79 | + T <: A & B |
| 80 | +
|
| 81 | + A <: T |
| 82 | + ---------------- |
| 83 | + A & B <: T |
| 84 | +
|
| 85 | + B <: T |
| 86 | + ---------------- |
| 87 | + A & B <: T |
| 88 | +``` |
| 89 | + |
| 90 | +From the rules above, we can show that `&` is _commutative_: `A & B <: B & A`. |
| 91 | +In another word, `A & B` is the same type as `B & A`, in that sense that the two types |
| 92 | +have the same values and are subtypes of each other. |
| 93 | + |
| 94 | +## Erasure |
| 95 | + |
| 96 | +The erased type for `S & T` is the erased _glb_ (greatest lower bound) of the |
| 97 | +erased type of `S` and `T`. The rules for erasure of intersection types are given |
| 98 | +below in pseudocode: |
| 99 | + |
| 100 | +``` |
| 101 | +|S & T| = glb(|S|, |T|) |
| 102 | +
|
| 103 | +glb(JArray(A), JArray(B)) = JArray(glb(A, B)) |
| 104 | +glb(JArray(T), _) = JArray(T) |
| 105 | +glb(_, JArray(T)) = JArray(T) |
| 106 | +glb(A, B) = A if A extends B |
| 107 | +glb(A, B) = B if B extends A |
| 108 | +glb(A, _) = A if A is not a trait |
| 109 | +glb(_, B) = B if B is not a trait |
| 110 | +glb(A, _) = A |
| 111 | +``` |
| 112 | + |
| 113 | +## Relationship with Compound Type (`with`) |
| 114 | + |
| 115 | +Intersection types `A & B` replace compound types `A with B` in Scala 2. For the |
| 116 | +moment, the syntax `A with B` is still allowed and interpreted as `A & B`, but |
| 117 | +its usage as a type (as opposed to in a `new` or `extends` clause) will be |
| 118 | +deprecated and removed in the future. |
0 commit comments