|
| 1 | +--- |
| 2 | +layout: doc-page |
| 3 | +title: "Intersection Types - More Details" |
| 4 | +--- |
| 5 | + |
| 6 | +## Syntax |
| 7 | + |
| 8 | +Syntactically, an intersection type `S & T` is similar to an infix type, where |
| 9 | +the infix operator is `&`. `&` is treated as a soft keyword. That is, it is a |
| 10 | +normal identifier with the usual precedence. But a type of the form `A & B` is |
| 11 | +always recognized as an intersection type, without trying to resolve `&`. |
| 12 | + |
| 13 | +``` |
| 14 | +Type ::= ...| InfixType |
| 15 | +InfixType ::= RefinedType {id [nl] RefinedType} |
| 16 | +``` |
| 17 | + |
| 18 | +## Subtyping Rules |
| 19 | + |
| 20 | +``` |
| 21 | +T <: A T <: B |
| 22 | +---------------- |
| 23 | + T <: A & B |
| 24 | +
|
| 25 | + A <: T |
| 26 | +---------------- |
| 27 | + A & B <: T |
| 28 | +
|
| 29 | + B <: T |
| 30 | +---------------- |
| 31 | + A & B <: T |
| 32 | +``` |
| 33 | + |
| 34 | +From the rules above, we can show that `&` is _commutative_: `A & B <: B & A` for any type `A` and `B`. |
| 35 | + |
| 36 | +``` |
| 37 | + B <: B A <: A |
| 38 | +---------- ----------- |
| 39 | +A & B <: B A & B <: A |
| 40 | +--------------------------- |
| 41 | + A & B <: B & A |
| 42 | +``` |
| 43 | + |
| 44 | +In another word, `A & B` is the same type as `B & A`, in the sense that the two types |
| 45 | +have the same values and are subtypes of each other. |
| 46 | + |
| 47 | +If `C` is a type constructor, the join `C[A] & C[B]` is simplified by pulling the |
| 48 | +intersection inside the constructor, using the following two rules: |
| 49 | + |
| 50 | +- If `C` is covariant, `C[A] & C[B] ~> C[A & B]` |
| 51 | +- If `C` is contravariant, `C[A] & C[B] ~> C[A | B]` |
| 52 | + |
| 53 | +When `C` is covariant, `C[A & B] <: C[A] & C[B]` can be derived: |
| 54 | + |
| 55 | +``` |
| 56 | + A <: A B <: B |
| 57 | + ---------- --------- |
| 58 | + A & B <: A A & B < B |
| 59 | +--------------- ----------------- |
| 60 | +C[A & B] <: C[A] C[A & B] <: C[B] |
| 61 | +------------------------------------------ |
| 62 | + C[A & B] <: C[A] & C[B] |
| 63 | +``` |
| 64 | + |
| 65 | +When `C` is contravariant, `C[A | B] <: C[A] & C[B]` can be derived: |
| 66 | + |
| 67 | +``` |
| 68 | + A <: A B <: B |
| 69 | + ---------- --------- |
| 70 | + A <: A | B B < A | B |
| 71 | +------------------- ---------------- |
| 72 | +C[A | B] <: C[A] C[A | B] <: C[B] |
| 73 | +-------------------------------------------------- |
| 74 | + C[A | B] <: C[A] & C[B] |
| 75 | +``` |
| 76 | + |
| 77 | +## Erasure |
| 78 | + |
| 79 | +The erased type for `S & T` is the erased _glb_ (greatest lower bound) of the |
| 80 | +erased type of `S` and `T`. The rules for erasure of intersection types are given |
| 81 | +below in pseudocode: |
| 82 | + |
| 83 | +``` |
| 84 | +|S & T| = glb(|S|, |T|) |
| 85 | +
|
| 86 | +glb(JArray(A), JArray(B)) = JArray(glb(A, B)) |
| 87 | +glb(JArray(T), _) = JArray(T) |
| 88 | +glb(_, JArray(T)) = JArray(T) |
| 89 | +glb(A, B) = A if A extends B |
| 90 | +glb(A, B) = B if B extends A |
| 91 | +glb(A, _) = A if A is not a trait |
| 92 | +glb(_, B) = B if B is not a trait |
| 93 | +glb(A, _) = A |
| 94 | +``` |
| 95 | + |
| 96 | +In the above, `|T|` means the erased type of `T`, `JArray` refers to |
| 97 | +the type of Java Array. |
| 98 | + |
| 99 | +## Relationship with Compound Type (`with`) |
| 100 | + |
| 101 | +Intersection types `A & B` replace compound types `A with B` in Scala 2. For the |
| 102 | +moment, the syntax `A with B` is still allowed and interpreted as `A & B`, but |
| 103 | +its usage as a type (as opposed to in a `new` or `extends` clause) will be |
| 104 | +deprecated and removed in the future. |
0 commit comments