|
| 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 | + |
0 commit comments