diff --git a/docs/_includes/features.html b/docs/_includes/features.html index 34e091d7c4f7..1181b36f7965 100644 --- a/docs/_includes/features.html +++ b/docs/_includes/features.html @@ -9,11 +9,7 @@

So, features?

- Union, intersection and literal singleton types - Implemented - - - Fast compilation (phase fusion) + Union, intersection and literal singleton types Implemented @@ -24,56 +20,40 @@

So, features?

@@static methods and fields Implemented - - Improved REPL with colors + + SBT incremental build Implemented - Sbt incremental build + Option-less pattern matching Implemented - Non-blocking lazy vals + Automatic tupling of function parameters Implemented - Option-less pattern matching (based on name-based patmat) - Implemented - - - Function arity adaptation + Multiversal equality Implemented - Multiversal equality + Phantom types Implemented - Exhaustivity checks in pattern matching + Implicit function types Implemented - - Non-boxed arrays of value classes - In progress - - Working contravariant implicits - In progress - - Auto-Specialization In progress - - Whole program optimizer - In progress - - HList & HMaps/Record types + Whole program optimizer In progress - Phantom types + HList & HMaps/Record types In progress @@ -81,33 +61,24 @@

So, features?

- Implicit functions - Considered - - Effects Considered - - Auto-completion in repl - Considered - - - Spec Option-less pattern matching - Considered -

Talks on Dotty?

I have more questions!

That’s great! We have more details on the docs and please join our Gitter channel!

+
diff --git a/docs/docs/reference/changed/pattern-matching.md b/docs/docs/reference/changed/pattern-matching.md new file mode 100644 index 000000000000..82b1645d759d --- /dev/null +++ b/docs/docs/reference/changed/pattern-matching.md @@ -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: + + + +```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: + + + +```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`. + + + +```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` + + + +```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. diff --git a/docs/sidebar.yml b/docs/sidebar.yml index 42bc9da7b42b..df973971d8dc 100644 --- a/docs/sidebar.yml +++ b/docs/sidebar.yml @@ -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 diff --git a/tests/new/patmat-spec.check b/tests/new/patmat-spec.check new file mode 100644 index 000000000000..0414b1106038 --- /dev/null +++ b/tests/new/patmat-spec.check @@ -0,0 +1,4 @@ +even has an even number of characters +First: H; Second: i +e,x,a,m +5 is a natural number diff --git a/tests/run/patmat-spec.scala b/tests/run/patmat-spec.scala new file mode 100644 index 000000000000..b4919e205d74 --- /dev/null +++ b/tests/run/patmat-spec.scala @@ -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 + } +}