Skip to content

Commit 1a901ec

Browse files
oderskyfelixmulder
authored andcommitted
Add sectionon union types
1 parent c6c27f6 commit 1a901ec

File tree

5 files changed

+104
-1
lines changed

5 files changed

+104
-1
lines changed

docs/docs/reference/intersection-types.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,4 +63,3 @@ class C extends A with B {
6363
def children: List[A & B] = ???
6464
}
6565
```
66-

docs/docs/reference/union-types.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
---
2+
layout: doc-page
3+
title: "Union Types"
4+
---
5+
6+
Used on types, the `|` operator creates a union type.
7+
8+
```scala
9+
case class UserName(name: String) {
10+
def lookup(admin: Admin): UserData
11+
}
12+
case class Password(hash: Hash) {
13+
def lookup(admin: Admin): UserData
14+
}
15+
16+
def help(id: UserName | PassWord) = {
17+
val user = id match {
18+
case UserName(name) => lookupName(name)
19+
case Password(hash) => lookupPassword(hash)
20+
}
21+
// ...
22+
}
23+
```
24+
25+
Union types are dual of intersection types. Values of type `A | B` are
26+
all values of type `A` and all values of type `B`. `|` is _commutative_:
27+
`A | B` is the same type as `B | A`.
28+
29+
The compiler will assign an expression a union type only if such a
30+
type is explicitly given.
31+
This can be seen in the folling REPL
32+
transcript:
33+
34+
```scala
35+
scala> val password = Password(123)
36+
val password: Password = Password(123)
37+
scala> val name = UserName("Eve")
38+
val name: UserName = UserName(Eve)
39+
scala> if (true) name else password
40+
val res2: Object & Product = UserName(Eve)
41+
scala> val either: Password | UserName = if (true) name else password
42+
val either: Password | UserName = UserName(Eve)
43+
```
44+
45+
The type of `res2` is `Object | Product`, which is a supertype of
46+
`UserName` and `Product, but not the least supertype `Password |
47+
UserName`. If we want the least supertype, we have to give it
48+
explicitely, as is done for the type of `Either`. More precisely, the
49+
typechecker will _widen_ a union type to a non-union type when
50+
inferring the type of ` `val` or `var`, or the result type of a `def`,
51+
or the argument to pass for a type parameter. The widened type of `A
52+
| B` is usually the intersection of all class or trait types that are
53+
supertypes of both `A` and `B`; it does not include any refinements.
54+
Union types are in that sense analogous to singleton types `x.type`
55+
which are also widened to their underlying type unless explicitly
56+
specified.
57+

docs/sidebar.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ sidebar:
33
url: blog/index.html
44
- title: Reference
55
subsection:
6+
- title: Intersection types
7+
url: docs/reference/intersection-types.html
8+
- title: Union types
9+
url: docs/reference/union-types.html
610
- title: Trait Parameters
711
url: docs/reference/trait-parameters.html
812
- title: Enumerations

tests/pos/intersection.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,10 @@ object intersection {
1515

1616
type needsA = A => Nothing
1717
type needsB = B => Nothing
18+
19+
20+
class C[-T]
21+
def f: C[A] & C[B] = ???
22+
def g: C[A | B] = f
23+
def h: C[A] & C[B] = g
1824
}

tests/pos/reference/union-types.scala

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package unionTypes
2+
3+
object t1 {
4+
5+
type Hash = Int
6+
7+
case class UserName(name: String)
8+
case class Password(hash: Hash)
9+
10+
def help(id: UserName | Password) = {
11+
val user = id match {
12+
case UserName(name) => lookupName(name)
13+
case Password(hash) => lookupPassword(hash)
14+
}
15+
}
16+
17+
def lookupName(name: String) = ???
18+
def lookupPassword(hash: Hash) = ???
19+
20+
}
21+
22+
object t2 {
23+
import t1._
24+
25+
trait Admin
26+
trait UserData
27+
28+
trait L { def lookup(admin: Admin): Object }
29+
30+
case class UserName(name: String) extends L {
31+
def lookup(admin: Admin): UserData = ???
32+
}
33+
case class Password(hash: Hash) extends L {
34+
def lookup(admin: Admin): UserData = ???
35+
}
36+
37+
}

0 commit comments

Comments
 (0)