Skip to content

Commit a964e04

Browse files
committed
Update spec for pattern match
1 parent 21c6fd0 commit a964e04

File tree

1 file changed

+127
-33
lines changed

1 file changed

+127
-33
lines changed

docs/docs/reference/changed-features/pattern-matching.md

Lines changed: 127 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,74 @@ Dotty implementation of pattern matching was greatly simplified compared to scal
77

88
Dotty supports a superset of scalac's [extractors](https://www.scala-lang.org/files/archive/spec/2.13/08-pattern-matching.html#extractor-patterns).
99

10-
## Boolean Pattern
10+
## Extractors
1111

12-
- Extractor defines `def unapply(x: T): Boolean`
12+
Extractors are objects that expose a method `unapply` or `unapplySeq`:
13+
14+
```Scala
15+
def unapply[A](x: T)(implicit x: B): U
16+
def unapplySeq[A](x: T)(implicit x: B): U
17+
```
18+
19+
Extractors expose the method `unapply` are called fix-arity extractors, which
20+
work with patterns of fixed arity. Extractors expose the method `unapplySeq` are
21+
called variadic extractors, which enables variadic patterns.
22+
23+
### Fixed-Arity Extractors
24+
25+
Fixed-arity extractors expose the following signature:
26+
27+
```Scala
28+
def unapply[A](x: T)(implicit x: B): U
29+
```
30+
31+
The type `U` conforms to one of the following matches:
32+
33+
- Boolean match
34+
- Product match
35+
36+
Or `U` conforms to the type `R`:
37+
38+
```Scala
39+
type R = {
40+
def isEmpty: Boolean
41+
def get: S
42+
}
43+
```
44+
45+
and `S` conforms to one of the following matches:
46+
47+
- Single match
48+
- Name-based match
49+
50+
51+
### Variadic Extractors
52+
53+
Variadic extractors expose the following signature:
54+
55+
```Scala
56+
def unapplySeq[A](x: T)(implicit x: B): U
57+
```
58+
59+
The type `U` conforms to one of the following matches:
60+
61+
- Sequence match
62+
- Product-sequence match
63+
64+
Or `U` conforms to the type `R`:
65+
66+
```Scala
67+
type R = {
68+
def isEmpty: Boolean
69+
def get: S
70+
}
71+
```
72+
73+
and `S` conforms to one of the two matches above.
74+
75+
## Boolean Match
76+
77+
- `U =:= Boolean`
1378
- Pattern-matching on exactly `0` patterns
1479

1580
For example:
@@ -28,10 +93,8 @@ object Even {
2893
// even has an even number of characters
2994
```
3095

96+
## Product Match
3197

32-
## Product Pattern
33-
34-
- Extractor defines `def unapply(x: T): U`
3598
- `U <: Product`
3699
- `N > 0` is the maximum number of consecutive (parameterless `def` or `val`) `_1: P1` ... `_N: PN` members in `U`
37100
- Pattern-matching on exactly `N` patterns with types `P1, P2, ..., PN`
@@ -62,12 +125,53 @@ object FirstChars {
62125
// First: H; Second: i
63126
```
64127

128+
## Single Match
129+
130+
- If there is exactly `1` pattern, pattern-matching on `1` pattern with type `U`
131+
132+
<!-- To be kept in sync with tests/new/patmat-spec.scala -->
133+
134+
```scala
135+
class Nat(val x: Int) {
136+
def get: Int = x
137+
def isEmpty = x < 0
138+
}
139+
140+
object Nat {
141+
def unapply(x: Int): Nat = new Nat(x)
142+
}
143+
144+
5 match {
145+
case Nat(n) => println(s"$n is a natural number")
146+
case _ => ()
147+
}
148+
// 5 is a natural number
149+
```
150+
151+
## Name-based Match
152+
153+
- `N > 1` is the maximum number of consecutive (parameterless `def` or `val`) `_1: P1 ... _N: PN` members in `U`
154+
- Pattern-matching on exactly `N` patterns with types `P1, P2, ..., PN`
155+
156+
```Scala
157+
object ProdEmpty {
158+
def _1: Int = ???
159+
def _2: String = ???
160+
def isEmpty = true
161+
def unapply(s: String): this.type = this
162+
def get = this
163+
}
164+
165+
"" match {
166+
case ProdEmpty(_, _) => ???
167+
case _ => ()
168+
}
169+
```
170+
65171

66-
## Name-based Seq Pattern
172+
## Seq Match
67173

68-
- Extractor defines `def unapplySeq(x: T): U`
69-
- `U` has (parameterless `def` or `val`) members `isEmpty: Boolean` and `get: S`
70-
- `S` conforms to `X`, `T2` and `T3` conform to `T1`
174+
- `U <: X`, `T2` and `T3` conform to `T1`
71175

72176
```Scala
73177
type X = {
@@ -97,32 +201,22 @@ object CharList {
97201
// e,x,a,m
98202
```
99203

204+
## Product-Seq Match
100205

101-
## Name-based Pattern
102-
103-
- Extractor defines `def unapply(x: T): U`
104-
- `U` has (parameterless `def` or `val`) members `isEmpty: Boolean` and `get: S`
105-
- If there is exactly `1` pattern, pattern-matching on `1` pattern with type `S`
106-
- Otherwise `N > 0` is the maximum number of consecutive (parameterless `def` or `val`) `_1: P1` ... `_N: PN` members in `U`
107-
- Pattern-matching on exactly `N` patterns with types `P1, P2, ..., PN`
108-
109-
<!-- To be kept in sync with tests/new/patmat-spec.scala -->
110-
111-
```scala
112-
class Nat(val x: Int) {
113-
def get: Int = x
114-
def isEmpty = x < 0
115-
}
206+
- `U <: Product`
207+
- `N > 0` is the maximum number of consecutive (parameterless `def` or `val`) `_1: P1` ... `_N: PN` members in `U`
208+
- `PN` conforms to the signature `X` defined in Seq Pattern
209+
- Pattern-matching on exactly `>= N` patterns, the first `N - 1` patterns have types `P1, P2, ... P(N-1)`,
210+
the type of the remaining patterns are determined as in Seq Pattern.
116211

117-
object Nat {
118-
def unapply(x: Int): Nat = new Nat(x)
212+
```Scala
213+
class Foo(val name: String, val children: Int *)
214+
object Foo {
215+
def unapplySeq(f: Foo): Option[(String, Seq[Int])] = Some((f.name, f.children))
119216
}
120217

121-
5 match {
122-
case Nat(n) => println(s"$n is a natural number")
123-
case _ => ()
218+
def foo(f: Foo) = f match {
219+
case Foo(name, ns : _*) =>
220+
case Foo(name, x, y, ns : _*) =>
124221
}
125-
// 5 is a natural number
126-
```
127-
128-
In case of ambiguities, *Product Pattern* is preferred over *Name Based Pattern*. This document reflects the state of pattern matching as currently implemented in Dotty. There are plans for further simplification, in particular to factor out *Product Pattern* and *Name Based Pattern* into a single type of extractor.
222+
```

0 commit comments

Comments
 (0)