Skip to content

Pattern matching documentation #2565

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

Merged
merged 2 commits into from
May 31, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 13 additions & 42 deletions docs/_includes/features.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,7 @@ <h1 id="so-features">So, features?</h1>
</colgroup>
<tbody>
<tr class="odd">
<td>Union, intersection and <a href="http://docs.scala-lang.org/sips/pending/42.type.html">literal singleton types</a></td>
<td>Implemented</td>
</tr>
<tr class="even">
<td>Fast compilation (phase fusion)</td>
<td><a href="http://dotty.epfl.ch/docs/reference/union-types.html">Union</a>, <a href="http://dotty.epfl.ch/docs/reference/intersection-types.html">intersection</a> and <a href="http://docs.scala-lang.org/sips/pending/42.type.html">literal singleton types</a></td>
<td>Implemented</td>
</tr>
<tr class="odd">
Expand All @@ -24,90 +20,65 @@ <h1 id="so-features">So, features?</h1>
<td><a href="https://github.com/scala/scala.github.com/pull/491">@@static methods and fields</a></td>
<td>Implemented</td>
</tr>
<tr class="odd">
<td>Improved REPL with colors</td>
<tr class="even">
<td><a href="http://dotty.epfl.ch/#getting-started">SBT incremental build</a></td>
<td>Implemented</td>
</tr>
<tr class="even">
<td>Sbt incremental build</td>
<td><a href="http://dotty.epfl.ch/docs/reference/pattern-matching.html"></a>Option-less pattern matching</td>
<td>Implemented</td>
</tr>
<tr class="odd">
<td>Non-blocking lazy vals</td>
<td><a href="http://dotty.epfl.ch/docs/reference/auto-parameter-tupling.html">Automatic tupling of function parameters</a></td>
<td>Implemented</td>
</tr>
<tr class="even">
<td>Option-less pattern matching (based on <a href="https://github.com/scala/scala/pull/2848">name-based patmat</a>)</td>
<td>Implemented</td>
</tr>
<tr class="odd">
<td>Function arity adaptation</td>
<td><a href="http://dotty.epfl.ch/docs/reference/multiversal-equality.html">Multiversal equality</a></td>
<td>Implemented</td>
</tr>
<tr class="even">
<td>Multiversal equality</td>
<td><a href="http://dotty.epfl.ch/docs/reference/phantom-types.html">Phantom types</a></td>
<td>Implemented</td>
</tr>
<tr class="odd">
<td>Exhaustivity checks in pattern matching</td>
<td><a href="http://dotty.epfl.ch/docs/reference/implicit-function-types.html">Implicit function types</a></td>
<td>Implemented</td>
</tr>
<tr class="even">
<td>Non-boxed arrays of value classes</td>
<td>In progress</td>
</tr>
<tr class="odd">
<td>Working contravariant implicits</td>
<td>In progress</td>
</tr>
<tr class="even">
<td><a href="https://github.com/dotty-linker/dotty">Auto-Specialization</a></td>
<td>In progress</td>
</tr>
<tr class="odd">
<td><a href="https://github.com/dotty-linker/dotty">Whole program optimizer</a></td>
<td>In progress</td>
</tr>
<tr class="even">
<td>HList &amp; HMaps/Record types</td>
<td><a href="https://github.com/lampepfl/dotty/pull/1840">Whole program optimizer</a></td>
<td>In progress</td>
</tr>
<tr class="odd">
<td>Phantom types</td>
<td><a href="https://github.com/lampepfl/dotty/pull/2199"></a>HList &amp; HMaps/Record types</td>
<td>In progress</td>
</tr>
<tr class="even">
<td></td>
<td></td>
</tr>
<tr class="odd">
<td>Implicit functions</td>
<td>Considered</td>
</tr>
<tr class="even">
<td>Effects</td>
<td>Considered</td>
</tr>
<tr class="odd">
<td>Auto-completion in repl</td>
<td>Considered</td>
</tr>
<tr class="even">
<td>Spec Option-less pattern matching</td>
<td>Considered</td>
</tr>
</tbody>
</table>
</div>
<h1 id="talks-on-dotty">Talks on Dotty?</h1>
<ul>
<li><a href="https://www.youtube.com/watch?v=GHzWqJKFCk4">Scala's Road Ahead</a> by Martin Odersky (<a href="http://www.slideshare.net/Odersky/scala-days-nyc-2016">slides</a>)</li>
<li><a href="https://www.youtube.com/watch?v=WxyyJyB_Ssc">Compilers are Databases</a> by Martin Odersky (<a href="http://www.slideshare.net/Odersky/compilers-are-databases">slides</a>)</li>
<li><a href="https://www.youtube.com/watch?v=aftdOFuVU1o">Exploring the future of Scala</a> by Dmitry Petrashko (<a href="https://d-d.me/scalaworld2015/#/">slides</a>)</li>
<p><a href="http://dotty.epfl.ch/docs/resources/talks.html#deep-dive-with-dotty">Deep Dive with Dotty</a></p>
</ul>
<h1 id="i-have-more-questions">I have more questions!</h1>
<div class="centered-text">
<p>That’s great! We have more details on the <a href="{{ site.baseurl }}/docs">docs</a> and please join our <a href="https://gitter.im/lampepfl/dotty">Gitter channel</a>!</p>
</div>
<br/>
</div>
<div class="centered-subtitle">
<a href="#why-dotty">
Expand Down
117 changes: 117 additions & 0 deletions docs/docs/reference/changed/pattern-matching.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
---
layout: doc-page
title: "Option-less pattern matching"
---

Dotty implementation of pattern matching was greatly simplified compared to scalac. From a user perspective, this means that Dotty generated patterns are a *lot* easier to debug, as variables all show up in debug modes and positions are correctly preserved.

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

## Boolean Pattern

- Extractor defines `def unapply(x: T): Boolean`
- Pattern-matching on exactly `0` patterns

For example:

<!-- To be kept in sync with tests/new/patmat-spec.scala -->

```scala
object Even {
def unapply(s: String): Boolean = s.size % 2 == 0
}

"even" match {
case s @ Even() => println(s"$s has an even number of characters")
case s => println(s"$s has an odd number of characters")
}
// even has an even number of characters
```


## Product Pattern

- Extractor defines `def unapply(x: T): U`
- `U <: Product`
- `N > 0` is the maximum number of consecutive (parameterless `def` or `val`) `_1: P1` ... `_N: PN` members in `U`
- Pattern-matching on exactly `N` patterns with types `P1, P2, ..., PN`

For example:

<!-- To be kept in sync with tests/new/patmat-spec.scala -->

```scala
class FirstChars(s: String) extends Product {
def _1 = s.charAt(0)
def _2 = s.charAt(1)

// Not used by pattern matching: Product is only used as a marker trait.
def canEqual(that: Any): Boolean = ???
def productArity: Int = ???
def productElement(n: Int): Any = ???
}

object FirstChars {
def unapply(s: String): FirstChars = new FirstChars(s)
}

"Hi!" match {
case FirstChars(char1, char2) =>
println(s"First: $char1; Second: $char2")
}
// First: H; Second: i
```


## Seq Pattern

- Extractor defines `def unapplySeq(x: T): U`
- `U` has (parameterless `def` or `val`) members `isEmpty: Boolean` and `get: S`
- `S <: Seq[V]`
- Pattern-matching on `N` pattern with types `V, V, ..., V`, where `N` is the runtime size of the `Seq`.

<!-- To be kept in sync with tests/new/patmat-spec.scala -->

```scala
object CharList {
def unapplySeq(s: String): Option[Seq[Char]] = Some(s.toList)
}

"example" match {
case CharList(c1, c2, c3, c4, _, _, _) =>
println(s"$c1,$c2,$c3,$c4")
case _ =>
println("Expected *exactly* 7 characters!")
}
// e,x,a,m
```


## Name Based Pattern

- Extractor defines `def unapply(x: T): U`
- `U` has (parameterless `def` or `val`) members `isEmpty: Boolean` and `get: S`
- If there is exactly `1` pattern, pattern-matching on `1` pattern with type `S`
- Otherwise `N > 0` is the maximum number of consecutive (parameterless `def` or `val`) `_1: P1` ... `_N: PN` members in `U`
- Pattern-matching on exactly `N` patterns with types `P1, P2, ..., PN`

<!-- To be kept in sync with tests/new/patmat-spec.scala -->

```scala
class Nat(val x: Int) {
def get: Int = x
def isEmpty = x < 0
}

object Nat {
def unapply(x: Int): Nat = new Nat(x)
}

5 match {
case Nat(n) => println(s"$n is a natural number")
case _ => ()
}
// 5 is a natural number
```

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. They are plans for further simplification, in particular to factor out *Product Pattern* and *Name Based Pattern* into a single type of extractor.
2 changes: 2 additions & 0 deletions docs/sidebar.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ sidebar:
url: docs/reference/changed/implicit-conversions.html
- title: Vararg Patterns
url: docs/reference/changed/vararg-patterns.html
- title: Pettern matching
url: docs/reference/changed/pattern-matching.html
- title: Dropped Features
subsection:
- title: DelayedInit
Expand Down
4 changes: 4 additions & 0 deletions tests/new/patmat-spec.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
even has an even number of characters
First: H; Second: i
e,x,a,m
5 is a natural number
61 changes: 61 additions & 0 deletions tests/run/patmat-spec.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// To be kept in sync with docs/docs/reference/pattern-matching.md
object Test {
def main(args: Array[String]): Unit = {
object Even {
def unapply(s: String): Boolean = s.size % 2 == 0
}

"even" match {
case s @ Even() => println(s"$s has an even number of characters")
case s => println(s"$s has an odd number of characters")
}
// even has an even number of characters

class FirstChars(s: String) extends Product {
def _1 = s.charAt(0)
def _2 = s.charAt(1)

// Not used by pattern matching: Product is only used as a marker trait.
def canEqual(that: Any): Boolean = ???
def productArity: Int = ???
def productElement(n: Int): Any = ???
}

object FirstChars {
def unapply(s: String): FirstChars = new FirstChars(s)
}

"Hi!" match {
case FirstChars(char1, char2) =>
println(s"First: $char1; Second: $char2")
}
// First: H; Second: i

object CharList {
def unapplySeq(s: String): Option[Seq[Char]] = Some(s.toList)
}

"example" match {
case CharList(c1, c2, c3, c4, _, _, _) =>
println(s"$c1,$c2,$c3,$c4")
case _ =>
println("Expected *exactly* 7 characters!")
}
// e,x,a,m

class Nat(val x: Int) {
def get: Int = x
def isEmpty = x < 0
}

object Nat {
def unapply(x: Int): Nat = new Nat(x)
}

5 match {
case Nat(n) => println(s"$n is a natural number")
case _ => ()
}
// 5 is a natural number
}
}