Skip to content

Commit d6fc56a

Browse files
committed
Add doc page
1 parent 5c9b7ec commit d6fc56a

File tree

3 files changed

+72
-1
lines changed

3 files changed

+72
-1
lines changed
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
---
2+
layout: doc-page
3+
title: "Pattern Bindings"
4+
---
5+
6+
In Scala 2, pattern bindings in `val` definitions and `for` expressions are
7+
loosely typed. Potentially failing matches are still accepted at compile-time,
8+
but may influence the program's runtime behavior.
9+
From Scala 3.1 on, type checking rules will be tightened so that errors are reported at compile-time instead.
10+
11+
## Bindings in Pattern Definitions
12+
13+
```scala
14+
val xs: List[Any] = List(1, 2, 3)
15+
val (x: String) :: _ xs // error: pattern's type String is more specialized
16+
// than the right hand side expression's type Any
17+
```
18+
This code gives a compile-time error in Scala 3.1 (and also in Scala 3.0 under the `-strict` setting) whereas it will fail at runtime with a `ClassCastException` in Scala 2. In Scala 3.1, a pattern binding is only allowed if the pattern is _irrefutable_, that is, if the right-hand side's type conforms to the pattern's type. For instance, the following is OK:
19+
```scala
20+
val pair = (1, true)
21+
val (x, y) = pair
22+
```
23+
Sometimes one wants to decompose data anyway, even though the pattern is refutable. For instance, if at some point one knows that a list `elems` is non-empty one might
24+
want to decompose it like this:
25+
```scala
26+
val first :: rest = elems // error
27+
```
28+
This works in Scala 2. In fact it is a typical use case for Scala 2's rules. But in Scala 3.1 it will give a type error. One can avoid the error by marking the pattern with an @unchecked annotation:
29+
```scala
30+
val first :: rest : @unchecked = elems // OK
31+
```
32+
This will make the compiler accept the pattern binding. It might give an error at runtime instead, if the underlying assumption that `elems` can never be empty is wrong.
33+
34+
## Pattern Bindings in For Expressions
35+
36+
Analogous changes apply to patterns in `for` expressions. For instance:
37+
38+
```scala
39+
val elems: List[Any] = List((1, 2), "hello", (3, 4))
40+
for ((x, y) <- elems) yield (y, x) // error: pattern's type (Any, Any) is more specialized
41+
// than the right hand side expression's type Any
42+
```
43+
This code gives a compile-time error in Scala 3.1 whereas in Scala 2 the list `elems`
44+
is filtered to retain only the elements of tuple type that match the pattern `(x, y)`.
45+
The filtering functionality can be obtained in Scala 3 by prefixing the pattern with `case`:
46+
```scala
47+
for (case (x, y) <- elems) yield (y, x) // returns List((2, 1), (4, 3))
48+
```
49+
50+
## Syntax Changes
51+
52+
There are two syntax changes relative to Scala 2: First, pattern definitions can carry ascriptions such as `: unchecked`. Second, generators in for expressions may be prefixed with `case`.
53+
```
54+
PatDef ::= ids [‘:’ Type] ‘=’ Expr
55+
| Pattern2 [‘:’ Type | Ascription] ‘=’ Expr
56+
Generator ::= [‘case’] Pattern1 ‘<-’ Expr
57+
```
58+
59+
## Migration
60+
61+
The new syntax is supported in Dotty and Scala 3.0. However, to enable smooth cross compilation between Scala 2 and Scala 3, the changed behavior and additional type checks are only enabled under the `-strict` setting. They will be enabled by default in version 3.1 of the language.
62+
63+
64+

docs/sidebar.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,9 @@ sidebar:
107107
url: docs/reference/changed-features/overload-resolution.html
108108
- title: Vararg Patterns
109109
url: docs/reference/changed-features/vararg-patterns.html
110-
- title: Pattern matching
110+
- title: Pattern Bindings
111+
url: docs/reference/changed-features/pattern-bindings.html
112+
- title: Pattern Matching
111113
url: docs/reference/changed-features/pattern-matching.html
112114
- title: Eta Expansion
113115
url: docs/reference/changed-features/eta-expansion.html

tests/neg-strict/filtering-fors.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ object Test {
1616
for (case (x: String) <- xs; (y, z) <- xs) do () // error
1717
for ((x: String) <- xs; case (y, z) <- xs) do () // error
1818

19+
val pairs: List[Any] = List((1, 2), (3, 4))
20+
for ((x, y) <- pairs) yield (y, x) // error
21+
1922
for (case x: String <- xs) do () // OK
2023
for (case (x: String) <- xs) do () // OK
2124
for (case y@ (x: String) <- xs) do () // OK
@@ -24,4 +27,6 @@ object Test {
2427
for (case (x: String) <- xs if x.isEmpty) do () // OK
2528
for (case (x: String) <- xs; y = x) do () // OK
2629
for (case (x: String) <- xs; case (y, z) <- xs) do () // OK
30+
31+
for (case (x, y) <- pairs) yield (y, x) // OK
2732
}

0 commit comments

Comments
 (0)