-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Add spec for intersection types #5233
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
--- | ||
layout: doc-page | ||
title: "Intersection Types - More Details" | ||
--- | ||
|
||
## Syntax | ||
|
||
Syntactically, an intersection type `S & T` is similar to an infix type, where | ||
the infix operator is `&`. `&` is treated as a soft keyword. That is, it is a | ||
normal identifier with the usual precedence. But a type of the form `A & B` is | ||
always recognized as an intersection type, without trying to resolve `&`. | ||
|
||
``` | ||
Type ::= ...| InfixType | ||
InfixType ::= RefinedType {id [nl] RefinedType} | ||
``` | ||
|
||
## Subtyping Rules | ||
|
||
``` | ||
T <: A T <: B | ||
---------------- | ||
T <: A & B | ||
|
||
A <: T | ||
---------------- | ||
A & B <: T | ||
|
||
B <: T | ||
---------------- | ||
A & B <: T | ||
``` | ||
|
||
From the rules above, we can show that `&` is _commutative_: `A & B <: B & A` for any type `A` and `B`. | ||
|
||
``` | ||
B <: B A <: A | ||
---------- ----------- | ||
A & B <: B A & B <: A | ||
--------------------------- | ||
A & B <: B & A | ||
``` | ||
|
||
In another word, `A & B` is the same type as `B & A`, in the sense that the two types | ||
have the same values and are subtypes of each other. | ||
|
||
If `C` is a type constructor, the join `C[A] & C[B]` is simplified by pulling the | ||
intersection inside the constructor, using the following two rules: | ||
|
||
- If `C` is covariant, `C[A] & C[B] ~> C[A & B]` | ||
- If `C` is contravariant, `C[A] & C[B] ~> C[A | B]` | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Where does the "simplified" terminology and the |
||
When `C` is covariant, `C[A & B] <: C[A] & C[B]` can be derived: | ||
|
||
``` | ||
A <: A B <: B | ||
---------- --------- | ||
A & B <: A A & B < B | ||
--------------- ----------------- | ||
C[A & B] <: C[A] C[A & B] <: C[B] | ||
------------------------------------------ | ||
C[A & B] <: C[A] & C[B] | ||
``` | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ahh ... I think my comment above should have been a follow up to this ... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch. The derivation provides partial justification for the simplification, as we cannot derive in the other direction. I tried to find examples where the rules are unsound, but failed. It seems the other direction can be justified informally. @odersky mentioned some theoretical work is needed here based on DOT. |
||
When `C` is contravariant, `C[A | B] <: C[A] & C[B]` can be derived: | ||
|
||
``` | ||
A <: A B <: B | ||
---------- --------- | ||
A <: A | B B < A | B | ||
------------------- ---------------- | ||
C[A | B] <: C[A] C[A | B] <: C[B] | ||
-------------------------------------------------- | ||
C[A | B] <: C[A] & C[B] | ||
``` | ||
|
||
## Erasure | ||
|
||
The erased type for `S & T` is the erased _glb_ (greatest lower bound) of the | ||
erased type of `S` and `T`. The rules for erasure of intersection types are given | ||
below in pseudocode: | ||
|
||
``` | ||
|S & T| = glb(|S|, |T|) | ||
|
||
glb(JArray(A), JArray(B)) = JArray(glb(A, B)) | ||
glb(JArray(T), _) = JArray(T) | ||
glb(_, JArray(T)) = JArray(T) | ||
glb(A, B) = A if A extends B | ||
glb(A, B) = B if B extends A | ||
glb(A, _) = A if A is not a trait | ||
glb(_, B) = B if B is not a trait | ||
glb(A, _) = A | ||
``` | ||
|
||
In the above, `|T|` means the erased type of `T`, `JArray` refers to | ||
the type of Java Array. | ||
|
||
## Relationship with Compound Type (`with`) | ||
|
||
Intersection types `A & B` replace compound types `A with B` in Scala 2. For the | ||
moment, the syntax `A with B` is still allowed and interpreted as `A & B`, but | ||
its usage as a type (as opposed to in a `new` or `extends` clause) will be | ||
deprecated and removed in the future. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,35 +1,36 @@ | ||
package intersectionTypes | ||
|
||
object t1 { | ||
trait Resetable { | ||
def reset(): this.type | ||
} | ||
|
||
trait Resetable { | ||
def reset(): this.type | ||
} | ||
trait Growable[T] { | ||
def add(x: T): this.type | ||
} | ||
def f(x: Resetable & Growable[String]) = { | ||
x.reset() | ||
x.add("first") | ||
} | ||
trait Growable[T] { | ||
def add(x: T): this.type | ||
} | ||
|
||
def f(x: Resetable & Growable[String]) = { | ||
x.reset() | ||
x.add("first") | ||
} | ||
} | ||
|
||
object t2 { | ||
|
||
trait A { | ||
def children: List[A] | ||
} | ||
trait B { | ||
def children: List[B] | ||
} | ||
val x: A & B = new C | ||
val ys: List[A & B] = x.children | ||
trait A { | ||
def children: List[A] | ||
} | ||
|
||
trait B { | ||
def children: List[B] | ||
} | ||
|
||
class C extends A with B { | ||
def children: List[A & B] = ??? | ||
} | ||
val x: A & B = new C | ||
val ys: List[A & B] = x.children | ||
|
||
class C extends A with B { | ||
def children: List[A & B] = ??? | ||
} | ||
|
||
val z: B & A = x // commutative | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Integrate the whole type checking section in the main page.