I'm trying to replicate the powerful pattern matching example that Joshua Suereth presented in his Devoxx 2013 talk titled "How to wield Scala in the trenches". Unfortunately I cannot achieve what he described and I cannot understand what is wrong. Can someone give me a hint at what I'm missing? (My Scala version is 2.10.3)
Please see the self contained code below:
case class Person(name: String, residence: Seq[Residence])
case class Residence(city: String, country: String)
object LivesIn {
def unapply(p: Person): Option[Seq[String]] =
Some(
for(r <- p.residence)
yield r.city
)
}
class StringSeqContains(value: String) {
def unapply(in: Seq[String]): Boolean =
in contains value
}
object PatternPower extends App {
val people =
Seq(Person("Emre", Seq(Residence("Antwerp", "BE"))),
Person("Ergin", Seq(Residence("Istanbul", "TR"))))
val Istanbul = new StringSeqContains("Istanbul")
// #1 does not work as expected, WHY?
println(
people collect {
case person @ LivesIn(Istanbul) => person
}
)
// #2 works as expected
println(
people collect {
case person @ LivesIn(cities) if cities.contains("Istanbul") => person
}
)
// #3 works as expected
println(
people collect {
case person @ Person(_, res) if res.contains(Residence("Istanbul", "TR")) => person
}
)
}
When I compile and run it I get:
List()
List(Person(Ergin,List(Residence(Istanbul,TR))))
List(Person(Ergin,List(Residence(Istanbul,TR))))
As denoted in the source code, I fail to grasp why the first pattern does not produce the same result as the remaining two pattern matches. Any ideas why?
Your LivesIn extractor requires a Seq for an argument.
The following variation does what you expect:
println(
people collect {
case person @ LivesIn(List("Istanbul")) => person
}
)
After some thinking and Googling, I realized that one should add ()
to the inner extractor (thanks to The Neophyte's Guide to Scala Part 1: Extractors).
In other words, the following works as expected:
people collect {
case person @ LivesIn(Istanbul()) => person
}
whereas the following code silently, without any complaints, returns List()
:
people collect {
case person @ LivesIn(Istanbul) => person
}
Unless I'm mistaken in another way (e.g. there is way to make it work without parantheses), I think technical presenters should be more careful with the code snippets / pseudo-code snippets (so that some of the curious audience will not lose sleepless hours ;-)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With