Skip to content

Commit 81d6978

Browse files
authored
Merge pull request #761 from travissarles/extractor-objects
Rewrote extractors section of tour
2 parents afa53a7 + 80b5e9c commit 81d6978

File tree

1 file changed

+29
-13
lines changed

1 file changed

+29
-13
lines changed

tutorials/tour/_posts/2017-02-13-extractor-objects.md

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,32 +11,48 @@ next-page: sequence-comprehensions
1111
previous-page: regular-expression-patterns
1212
---
1313

14-
In Scala, patterns can be defined independently of case classes. To this end, a method named unapply is defined to yield a so-called extractor. An extractor can be thought of as a special method that reverses the effect of applying a particular object on some inputs. Its purpose is to 'extract' the inputs that were present before the 'apply' operation. For instance, the following code defines an extractor [object](singleton-objects.html) Twice.
14+
An extractor object is an object with an `unapply` method. Whereas the `apply` method is like a constructor which takes arguments and creates an object, the `unapply` takes an object and tries to give back the arguments. This is most often used in pattern matching and partial functions.
1515

1616
```tut
17-
object Twice {
18-
def apply(x: Int): Int = x * 2
19-
def unapply(z: Int): Option[Int] = if (z%2 == 0) Some(z/2) else None
17+
import scala.util.Random
18+
19+
object CustomerID {
20+
21+
def apply(name: String) = s"$name--${Random.nextLong}"
22+
23+
def unapply(customerID: String): Option[String] = {
24+
val name = customerID.split("--").head
25+
if (name.nonEmpty) Some(name) else None
26+
}
2027
}
2128
22-
object TwiceTest extends App {
23-
val x = Twice(21)
24-
x match { case Twice(n) => Console.println(n) } // prints 21
29+
val customer1ID = CustomerID("Sukyoung") // Sukyoung--23098234908
30+
customer1ID match {
31+
case CustomerID(name) => println(name) // prints Sukyoung
32+
case _ => println("Could not extract a CustomerID")
2533
}
2634
```
2735

28-
There are two syntactic conventions at work here:
36+
The `apply` method creates a `CustomerID` string from a `name`. The `unapply` does the inverse to get the `name` back. When we call `CustomerID("Sukyoung")`, this is shorthand syntax for calling `CustomerID.apply("Sukyoung")`. When we call `case CustomerID(name) => customer1ID`, we're calling the unapply method.
2937

30-
The pattern `case Twice(n)` will cause an invocation of `Twice.unapply`, which is used to match any even number; the return value of the `unapply` signals whether the argument has matched or not, and any sub-values that can be used for further matching. Here, the sub-value is `z/2`
38+
The unapply method can also be used to assign a value.
3139

32-
The `apply` method is not necessary for pattern matching. It is only used to mimick a constructor. `val x = Twice(21)` expands to `val x = Twice.apply(21)`.
40+
```tut
41+
val customer2ID = CustomerID("Nico")
42+
val CustomerID(name) = customer2ID
43+
println(name) // prints Nico
44+
```
45+
46+
This is equivalent to `val name = CustomerID.unapply(customer2ID).get`. If there is no match, a `scala.MatchError` is thrown:
47+
48+
```tut:fail
49+
val CustomerID(name2) = "--asdfasdfasdf"
50+
```
3351

3452
The return type of an `unapply` should be chosen as follows:
3553

3654
* If it is just a test, return a `Boolean`. For instance `case even()`
3755
* If it returns a single sub-value of type T, return an `Option[T]`
3856
* If you want to return several sub-values `T1,...,Tn`, group them in an optional tuple `Option[(T1,...,Tn)]`.
3957

40-
Sometimes, the number of sub-values is fixed and we would like to return a sequence. For this reason, you can also define patterns through `unapplySeq`. The last sub-value type `Tn` has to be `Seq[S]`. This mechanism is used for instance in pattern `case List(x1, ..., xn)`.
41-
42-
Extractors can make code more maintainable. For details, read the paper ["Matching Objects with Patterns"](https://infoscience.epfl.ch/record/98468/files/MatchingObjectsWithPatterns-TR.pdf) (see section 4) by Emir, Odersky and Williams (January 2007).
58+
Sometimes, the number of sub-values is fixed and we would like to return a sequence. For this reason, you can also define patterns through `unapplySeq` which returns `Option[Seq[T]]` This mechanism is used for instance in pattern `case List(x1, ..., xn)`.

0 commit comments

Comments
 (0)