intro match {
!case PatternMatching()
!!!=> “Welcome”
}
Friday, September 6, 13
Who am I?
•Java & Scala developer at Schantz A/S
•Polyglot curious, Coursera junkie
•Interested in HCI and Usability
•https://github.com/JKrag
@jankrag
• Geek, builder and flyer of kites, reptile & cat breeder, Rubik's puzzle fan
Friday, September 6, 13
Pattern Matching
• A very powerful feature of Scala
• Java’s “switch” on steroids?
Friday, September 6, 13
Java’s switch
• lets you match a ‘value’ agains a number of
cases, and conditionally executes code
• basically only switch on numeric values
• int, byte, etc....
• (Yes, Java 7 has switch on String, but only
syntactic sugar.)
• Performance > nested if’s
Friday, September 6, 13
Scala’s ‘match’
• Lets you match a ‘value’ agains complex
patterns
• Can switch on multiple types
• Can match most kind of types by matching
agains the “creation form” of an object
(patience...)
Friday, September 6, 13
Scala’s match (cont.)
• Each “case” is a Scala expression, and thus
Each “match” block is an expression
• Can be used as a full function body...
Friday, September 6, 13
History
• Pattern matching is nothing new
• Has existed way back in functional
languages
• Most notable early example: ML
• Also found in Haskell, Erlang, OCaml etc.
Friday, September 6, 13
Lets get on with it...
Friday, September 6, 13
Syntax - simple “java like”
def weather(code: Int): String = {
code match {
case 1 => "sun"
case 0 => "rain"
case _ => "error"
}
}
“_” is used as wildcard for the “default” case, when we don’t
need the matched value...
Friday, September 6, 13
Syntax
def weather(code: Int) = code match {
case 1 => "sun"
case 0 => "rain"
case _ => "error"
}
match used directly as full function body
Friday, September 6, 13
multiple matches
def myPlans(weekday: Int) = weekday match {
! case 1 | 2 | 3 | 4 | 5 => "work"
! case 6 | 7 => "relax"
! case _ => "unknown weekday"
}
Friday, September 6, 13
Matching literals
• A literal pattern L matches any value that is
equal (in terms of ==) to the literal L.
Friday, September 6, 13
matching strings
def parseArgument(arg: String) = arg match {
case "-h" | "--help" => displayHelp
case "-v" | "--version" => displayVerion
case whatever => unknownArgument(whatever)
}
Friday, September 6, 13
Mixed stuff
def handle(msg: Any) = msg match {
! "QUIT" => "recieved stop request"
! 42 => "The answer to the ultimate question"
! _ => "something else"
}
Friday, September 6, 13
matching tuples
def moveTo(coord: Any) = coord match {
! case (_, _) => println("received good 2D coord.")
! case (_, _ , _) => println("3D not supported")
! case _ => println("unexpected stuff")
}
Friday, September 6, 13
matching on types
• In java, if you need to “detect” types, you
typically use “instance of” and typecast
• In scala, we can match on types, using
variables, and these know the type
Friday, September 6, 13
types and variables
def handle(msg: Any) = msg match {
case i:Int => "Int'eresting: " + i
case _:Double => "Doubly so!"
case s:String => "You really want't me to do " + s
}
• introduced variables (typed of course)
• order can be important. Cases checked in
order
Friday, September 6, 13
matching tuples -
revisited
def moveTo(coord: Any) = coord match {
! case (a: Int, b: Int) => updateCoordinate(a, b)
! case (_, _ , _) => println("3D not supported")
! case _ => println("unexpected coordinate")
}
Friday, September 6, 13
variables
• In general, everything in lowercase is
treated as a “variable”
• constants should start with uppercase
Friday, September 6, 13
case matters
class Sample {
! val max = 100
! val MIN = 0
! def process(input: Int) {
! ! input match {
! ! ! case max => println("aaargh.")
! ! ! case MIN => println("matched MIN")
! ! ! case _ => println("unreachable")
! ! }
! }
}
What happens?
Friday, September 6, 13
case matters
class Sample {
! val max = 100
! val MIN = 0
! def process(input: Int) {
! ! input match {
! ! ! case max => println("aaargh.")
! ! ! case MIN => println("matched MIN")
! ! ! case _ => println("unreachable")
! ! }
! }
}
What happens?
Compile error
Friday, September 6, 13
case matters
class Sample {
! val max = 100
! val MIN = 0
! def process(input: Int) {
! ! input match {
! ! ! case max => println("aaargh.")
! ! ! case MIN => println("matched MIN")
! ! ! case _ => println("unreachable")
! ! }
! }
}
What happens?
Compile error
unreachable code
Friday, September 6, 13
case matters
class Sample {
! val max = 100
! val MIN = 0
! def process(input: Int) {
! ! input match {
! ! ! case max => println("aaargh.")
! ! ! case MIN => println("matched MIN")
! ! ! case _ => println("unreachable")
! ! }
! }
}
What happens?
Compile error
unreachable code
fix with: this.max
Friday, September 6, 13
Practical example:
Recursive factorial
• Without pattern matching:
def fact(n: Int): Int =
if (n == 0) 1
else n * fact(n - 1)
• With pattern matching:
def fact(n: Int): Int = n match {
case 0 => 1
case n => n * fact(n - 1)
}
• Note: n matches “everything else”
• Note: scope
Friday, September 6, 13
Matching List
• List("Apple", "Microsoft")
• List("Scala", "Clojure", "Groovy", _*)
• "array explosion symbol"
Friday, September 6, 13
look-alike
Friday, September 6, 13
look-alike
list match {
! ! case Nil => "was an empty list"
!! case x :: xs =>
"head was " + x + ", tail was " + xs
}
//remember a list in scala is either Nil, or “something
and a tail”
Friday, September 6, 13
look-alike
def length[A](list : List[A]) : Int = list match {
case _ :: tail => 1 + length(tail)
case Nil => 0
}
list match {
! ! case Nil => "was an empty list"
!! case x :: xs =>
"head was " + x + ", tail was " + xs
}
//remember a list in scala is either Nil, or “something
and a tail”
Friday, September 6, 13
Guards
• Powerful addition.
• Allows for “conditional” matching
Friday, September 6, 13
Guards - example
case msg : Int if (msg < 0) =>
printf("Execution problem. Return code: %d")
case msg : Int if (msg > 0) =>
printf("Succes. Return code: %d")
case _ : Int => printf("Boring")
Friday, September 6, 13
More advanced topics?
Quick breeze through
Friday, September 6, 13
Nested patterns
• case List(Cat(name), Owner(first, last))
Friday, September 6, 13
Nested - example
object Role extends Enumeration {
! type Role = Value
! val DEV, PM, CEO = Value
}
case class Name(first:String, last:String)
case class Person(name:Name, age:Int, role:Role)
val person = Person(Name("Jan", "Krag"), 42, Role.DEV)
person match {
! case Person(Name(first, last), age:Int, r: Role) =>
first + " " + last + " (aged " + age + ")"
! case _ => "something else"
}
//> res4: java.lang.String = "Jan Krag (aged 42) "
Friday, September 6, 13
Pattern binders
• We can assign a binder to part of a pattern
during a match using the @ notation.
• Often usefull when we want a larger part
of a pattern to use on the expression side
• e.g. case pers @ Person(“Dude”, _, _) =>
println(pers)
• binds pers to the whole Person object
Friday, September 6, 13
Regular expressions
val Name = """(w+)s+(w+)""".r
"Jan Krag" match {
case Name(first,last) => println("found: ", first, last)
case _ => println("oh no!")
}
(found: ,Jan,Krag)
Friday, September 6, 13
case classes
• Very common use case
• If case class is sealed abstract, compiler can
verify that match is exhaustive
• works because case classes have an auto-
generated unapply method.
Friday, September 6, 13
exhaustive match
sealed abstract class Expr
case class Var(name: String) extends Expr
case class Number(num: Double) extends Expr
case class UnOp(operator: String, arg: Expr) extends Expr
case class BinOp(operator: String, left: Expr, right: Expr)
extends Expr
def describe(e: Expr): String = e match {
case Number(_) => "a number"
case Var(_) => "a variable"
}
//warning: match is not exhaustive!
//missing combination UnOp
//missing combination BinOp
Friday, September 6, 13
Matching XML fragments
• As Scala has first class support for XML, we
can also match XML fragments:
case <price>{itemPrice}</price> =>
println("price was: " + itemPrice)
Friday, September 6, 13
Stable identifiers
def f(x: Int, y: Int) = x match {
case y => ...
}
def f(x: Int, y: Int) = x match {
case `y` => ...
}
Friday, September 6, 13
anomymous functions
• case classes can also be used as anonymous
functions, i..e. without a “match” clause:
• { case p1 => b1 ... case pn => bn }
Friday, September 6, 13
in Exception handling
try {
throw new j.i.IOException("no such file")
} catch {
case e @ (_ : RuntimeException | _ : j.i.IOException)
=> println(e)
}
// prints out "java.io.IOException: no such file"
Example also demonstrates binding of “alternatives”
expression
Friday, September 6, 13
Deconstructing
BillVenners: You said a pattern looks like an expression, but it
seems kind of like a backwards expression. Instead of
plugging values in and getting one result out, you put in one
value, and when it matches, a bunch of values pop back out.
Martin Odersky: Yes. It's really the exact reversal of
construction. I can construct objects with nested
constructors, and maybe I also have some parameters. Let's
say I have a method that takes some parameters and
constructs some complicated object structure from those
parameters. Pattern matching does the reverse. It takes a
complicated object structure and pulls out the parameters
that were used to construct the same structure.
Friday, September 6, 13
apply(...) / unapply(...)
• And this is a whole new (albeit important)
subject best left for next time...
Friday, September 6, 13

Intro to pattern matching in scala

  • 1.
    intro match { !casePatternMatching() !!!=> “Welcome” } Friday, September 6, 13
  • 2.
    Who am I? •Java& Scala developer at Schantz A/S •Polyglot curious, Coursera junkie •Interested in HCI and Usability •https://github.com/JKrag @jankrag • Geek, builder and flyer of kites, reptile & cat breeder, Rubik's puzzle fan Friday, September 6, 13
  • 3.
    Pattern Matching • Avery powerful feature of Scala • Java’s “switch” on steroids? Friday, September 6, 13
  • 4.
    Java’s switch • letsyou match a ‘value’ agains a number of cases, and conditionally executes code • basically only switch on numeric values • int, byte, etc.... • (Yes, Java 7 has switch on String, but only syntactic sugar.) • Performance > nested if’s Friday, September 6, 13
  • 5.
    Scala’s ‘match’ • Letsyou match a ‘value’ agains complex patterns • Can switch on multiple types • Can match most kind of types by matching agains the “creation form” of an object (patience...) Friday, September 6, 13
  • 6.
    Scala’s match (cont.) •Each “case” is a Scala expression, and thus Each “match” block is an expression • Can be used as a full function body... Friday, September 6, 13
  • 7.
    History • Pattern matchingis nothing new • Has existed way back in functional languages • Most notable early example: ML • Also found in Haskell, Erlang, OCaml etc. Friday, September 6, 13
  • 8.
    Lets get onwith it... Friday, September 6, 13
  • 9.
    Syntax - simple“java like” def weather(code: Int): String = { code match { case 1 => "sun" case 0 => "rain" case _ => "error" } } “_” is used as wildcard for the “default” case, when we don’t need the matched value... Friday, September 6, 13
  • 10.
    Syntax def weather(code: Int)= code match { case 1 => "sun" case 0 => "rain" case _ => "error" } match used directly as full function body Friday, September 6, 13
  • 11.
    multiple matches def myPlans(weekday:Int) = weekday match { ! case 1 | 2 | 3 | 4 | 5 => "work" ! case 6 | 7 => "relax" ! case _ => "unknown weekday" } Friday, September 6, 13
  • 12.
    Matching literals • Aliteral pattern L matches any value that is equal (in terms of ==) to the literal L. Friday, September 6, 13
  • 13.
    matching strings def parseArgument(arg:String) = arg match { case "-h" | "--help" => displayHelp case "-v" | "--version" => displayVerion case whatever => unknownArgument(whatever) } Friday, September 6, 13
  • 14.
    Mixed stuff def handle(msg:Any) = msg match { ! "QUIT" => "recieved stop request" ! 42 => "The answer to the ultimate question" ! _ => "something else" } Friday, September 6, 13
  • 15.
    matching tuples def moveTo(coord:Any) = coord match { ! case (_, _) => println("received good 2D coord.") ! case (_, _ , _) => println("3D not supported") ! case _ => println("unexpected stuff") } Friday, September 6, 13
  • 16.
    matching on types •In java, if you need to “detect” types, you typically use “instance of” and typecast • In scala, we can match on types, using variables, and these know the type Friday, September 6, 13
  • 17.
    types and variables defhandle(msg: Any) = msg match { case i:Int => "Int'eresting: " + i case _:Double => "Doubly so!" case s:String => "You really want't me to do " + s } • introduced variables (typed of course) • order can be important. Cases checked in order Friday, September 6, 13
  • 18.
    matching tuples - revisited defmoveTo(coord: Any) = coord match { ! case (a: Int, b: Int) => updateCoordinate(a, b) ! case (_, _ , _) => println("3D not supported") ! case _ => println("unexpected coordinate") } Friday, September 6, 13
  • 19.
    variables • In general,everything in lowercase is treated as a “variable” • constants should start with uppercase Friday, September 6, 13
  • 20.
    case matters class Sample{ ! val max = 100 ! val MIN = 0 ! def process(input: Int) { ! ! input match { ! ! ! case max => println("aaargh.") ! ! ! case MIN => println("matched MIN") ! ! ! case _ => println("unreachable") ! ! } ! } } What happens? Friday, September 6, 13
  • 21.
    case matters class Sample{ ! val max = 100 ! val MIN = 0 ! def process(input: Int) { ! ! input match { ! ! ! case max => println("aaargh.") ! ! ! case MIN => println("matched MIN") ! ! ! case _ => println("unreachable") ! ! } ! } } What happens? Compile error Friday, September 6, 13
  • 22.
    case matters class Sample{ ! val max = 100 ! val MIN = 0 ! def process(input: Int) { ! ! input match { ! ! ! case max => println("aaargh.") ! ! ! case MIN => println("matched MIN") ! ! ! case _ => println("unreachable") ! ! } ! } } What happens? Compile error unreachable code Friday, September 6, 13
  • 23.
    case matters class Sample{ ! val max = 100 ! val MIN = 0 ! def process(input: Int) { ! ! input match { ! ! ! case max => println("aaargh.") ! ! ! case MIN => println("matched MIN") ! ! ! case _ => println("unreachable") ! ! } ! } } What happens? Compile error unreachable code fix with: this.max Friday, September 6, 13
  • 24.
    Practical example: Recursive factorial •Without pattern matching: def fact(n: Int): Int = if (n == 0) 1 else n * fact(n - 1) • With pattern matching: def fact(n: Int): Int = n match { case 0 => 1 case n => n * fact(n - 1) } • Note: n matches “everything else” • Note: scope Friday, September 6, 13
  • 25.
    Matching List • List("Apple","Microsoft") • List("Scala", "Clojure", "Groovy", _*) • "array explosion symbol" Friday, September 6, 13
  • 26.
  • 27.
    look-alike list match { !! case Nil => "was an empty list" !! case x :: xs => "head was " + x + ", tail was " + xs } //remember a list in scala is either Nil, or “something and a tail” Friday, September 6, 13
  • 28.
    look-alike def length[A](list :List[A]) : Int = list match { case _ :: tail => 1 + length(tail) case Nil => 0 } list match { ! ! case Nil => "was an empty list" !! case x :: xs => "head was " + x + ", tail was " + xs } //remember a list in scala is either Nil, or “something and a tail” Friday, September 6, 13
  • 29.
    Guards • Powerful addition. •Allows for “conditional” matching Friday, September 6, 13
  • 30.
    Guards - example casemsg : Int if (msg < 0) => printf("Execution problem. Return code: %d") case msg : Int if (msg > 0) => printf("Succes. Return code: %d") case _ : Int => printf("Boring") Friday, September 6, 13
  • 31.
    More advanced topics? Quickbreeze through Friday, September 6, 13
  • 32.
    Nested patterns • caseList(Cat(name), Owner(first, last)) Friday, September 6, 13
  • 33.
    Nested - example objectRole extends Enumeration { ! type Role = Value ! val DEV, PM, CEO = Value } case class Name(first:String, last:String) case class Person(name:Name, age:Int, role:Role) val person = Person(Name("Jan", "Krag"), 42, Role.DEV) person match { ! case Person(Name(first, last), age:Int, r: Role) => first + " " + last + " (aged " + age + ")" ! case _ => "something else" } //> res4: java.lang.String = "Jan Krag (aged 42) " Friday, September 6, 13
  • 34.
    Pattern binders • Wecan assign a binder to part of a pattern during a match using the @ notation. • Often usefull when we want a larger part of a pattern to use on the expression side • e.g. case pers @ Person(“Dude”, _, _) => println(pers) • binds pers to the whole Person object Friday, September 6, 13
  • 35.
  • 36.
    case classes • Verycommon use case • If case class is sealed abstract, compiler can verify that match is exhaustive • works because case classes have an auto- generated unapply method. Friday, September 6, 13
  • 37.
    exhaustive match sealed abstractclass Expr case class Var(name: String) extends Expr case class Number(num: Double) extends Expr case class UnOp(operator: String, arg: Expr) extends Expr case class BinOp(operator: String, left: Expr, right: Expr) extends Expr def describe(e: Expr): String = e match { case Number(_) => "a number" case Var(_) => "a variable" } //warning: match is not exhaustive! //missing combination UnOp //missing combination BinOp Friday, September 6, 13
  • 38.
    Matching XML fragments •As Scala has first class support for XML, we can also match XML fragments: case <price>{itemPrice}</price> => println("price was: " + itemPrice) Friday, September 6, 13
  • 39.
    Stable identifiers def f(x:Int, y: Int) = x match { case y => ... } def f(x: Int, y: Int) = x match { case `y` => ... } Friday, September 6, 13
  • 40.
    anomymous functions • caseclasses can also be used as anonymous functions, i..e. without a “match” clause: • { case p1 => b1 ... case pn => bn } Friday, September 6, 13
  • 41.
    in Exception handling try{ throw new j.i.IOException("no such file") } catch { case e @ (_ : RuntimeException | _ : j.i.IOException) => println(e) } // prints out "java.io.IOException: no such file" Example also demonstrates binding of “alternatives” expression Friday, September 6, 13
  • 42.
    Deconstructing BillVenners: You saida pattern looks like an expression, but it seems kind of like a backwards expression. Instead of plugging values in and getting one result out, you put in one value, and when it matches, a bunch of values pop back out. Martin Odersky: Yes. It's really the exact reversal of construction. I can construct objects with nested constructors, and maybe I also have some parameters. Let's say I have a method that takes some parameters and constructs some complicated object structure from those parameters. Pattern matching does the reverse. It takes a complicated object structure and pulls out the parameters that were used to construct the same structure. Friday, September 6, 13
  • 43.
    apply(...) / unapply(...) •And this is a whole new (albeit important) subject best left for next time... Friday, September 6, 13