scala essentials - pattern matching and case classes
DESCRIPTION
In-depth presentation about basics of pattern matching and case classes given by Karel Smutný at the April's Czech Scala Enthusiasts meetup held at Faculty of Information Technology in Prague.TRANSCRIPT
CTU-FIT-SCA/scalaonfit
If you’re gonna code,download the following Gist
https://gist.github.com/ksmutny/5439360
Czech Scala Enthusiasts–April 23 2013
Scala Essentials: Pattern Matching and Case ClassesKarel Smutný–Agile Developer & Coach
switch statement
switch (whatIsThis) { case 8: case 10: doSomething(); break; case 12: doSomethingElse(); break; default: doDefault();}
match expression
whatIsThis match { case 8 | 10 => something case 12 => somethingElse case _ => default}
Pattern Matchinga.k.a.
Switch on steroids
Pattern Matchinga.k.a.
Batman’s toolbelt
https://gist.github.com/ksmutny/5439360sealed trait Character { def name: String}
case class Civilian( name: String, wealth: Wealth) extends Character
case class SuperHero( name: String, powers: List[Power], alterEgo: Option[Civilian]) extends Character
The ProblemWhat are the super powers of an unknown person if it is a super hero who’s alter ego is Tony Stark?
Javaif (unknownChar instanceof SuperHero) { final SuperHero hero = (SuperHero) unknownChar; if (hero.alterEgo.equals(tonyStark)) { return hero.powers; } else { return null; }} else { return null;}
ScalaunknownPerson match { case SuperHero(_, powers, Some(TonyStark)) => Some(powers) case _ => None}
ScalaunknownPerson match { case SuperHero(_, powers, Some(TonyStark)) => Some(powers) case _ => None}
How cool is that?
JavaScript
unknownPerson.hasOwnPropery(“powers”) ? unknownPerson[“powers”] : null;
Kinds of patterns
Wildcard patternwhatIsThis match { case _ => “anything!”}
Constant pattern
whatIsThis match { case 42 => “a magic no.” case “Hello!” => “a greeting” case math.Pi => “another magic no.” case _ => “something else”}
Constant patternevaluating { BruceWayne match { case 42 => “a magic no.” case “Hello!” => “a greeting” case math.Pi => “another magic no.” }} should produce[MatchError]
Variable pattern
whatIsThis match { case something => “not very useful?”}
Variable pattern
whatIsThis match { case whatIsThis => “not very useful?”}
Typed pattern
whatIsThis match { case n: Int => “aah, a number” case c: Character => “it’s ” + c.name}
Constructor pattern
unknownPerson match { case SuperHero(_, powers, Some(TonyStark)) => Some(powers) case _ => None}
Constant v Variable patternval TonyStark = Civilian(“Tony Stark”, Fortune)val BruceWayne = Civilian(“Bruce Wayne”, Fortune)val clarkKent = Civilian(“Clark Kent”, Cash(1000))
TonyStark match { case BruceWayne => “Batman!” case clarkKent => “isn’t this Superman?” case _ => “is he?”}
Constant v Variable patternval TonyStark = Civilian(“Tony Stark”, Fortune)val BruceWayne = Civilian(“Bruce Wayne”, Fortune)val clarkKent = Civilian(“Clark Kent”, Cash(1000))
TonyStark match { case BruceWayne => “Batman!” case `clarkKent` => “Superman!” case _ => “anybody”}
Constant v Variable patternval TonyStark = Civilian(“Tony Stark”, Fortune)val BruceWayne = Civilian(“Bruce Wayne”, Fortune)val clarkKent = Civilian(“Clark Kent”, Cash(1000))
TonyStark match { case BruceWayne => “Batman!” case `clarkKent` => “Superman!” case _ => “anybody”}
Constructor patternval powers = unknownPerson match { case SuperHero(_, powers, Some(TonyStark)) => Some(powers) case _ => None}
val firstPower = powers match { case Some(power :: rest) => power case _ => Genius}
Constructor patternval powers = unknownPerson match { case SuperHero(_, powers, Some(TonyStark)) => Some(powers) case _ => None}
val firstPower = powers match { case Some(power :: rest) => power case _ => Genius}
Constructor patternval powers = unknownPerson match { case SuperHero(_, powers, Some(TonyStark)) => Some(powers) case _ => None}
val firstPower = powers match { case Some(power :: rest) => power case _ => Genius}
Tuple patternaPair match { case (42, math.Pi, _) => “magic numbers + anything” case (IronMan, Mandarin) => “hate each other” case Tuple2(IronMan, Mandarin) => “alike” case (v: Villain, MaryJane) => “are cheating on Peter”}
Sequence pattern
powers match { case List(SuperStrength, _, _*) => “at least two”}
Pattern guard
aGuy match { case Civilian(_, Cash(money)) if cash >= 10000 => “Rich guy” case _ => “anybody else”}
Patterns everywhere
Variable definitionval (a, b) = someTupleval List(Flight, second, rest @ _*) = powersval Civilian(name, wealth: Cash) = clarkKent
Is this pattern matching, too?
val a = 3
Exceptions
try { doSomethingStupid()} catch { case e: IOException => … case e: SQLException => …}
Partial functionval numToStr: PartialFunction[Int, String] = { case 8 => “eight” case 10 => “ten”}
numToStr.isDefinedAt(12)
evaluating { numToStr(12)} should produce[??????????????]
For comprehensionsval lines = List( “1\t2,3\t3,12”, “2\t1,3\t3,15”, “3\t1,12\t2,15”)
val edges = for { line <- lines Array(srcNode, edges @ _*) = line split “\t” edge <- edges Array(destNode, length) = edge split “,”} yield Edge(srcNode.toInt, destNode.toInt, length.toInt)
For comprehensions. Beware!
val egos = for { hero : SuperHero <- characters // does not work} yield hero.alterEgo
val egos = for { hero @ (h : SuperHero) <- characters} yield hero.alterEgo
Extractors
Extractors
trait Person { def name: String def age: Int}
object Person { def unapply(person: Person): Option[(String, Int)] = Some((person.name, age))}
somePerson match { case Person(“Moses”, _) => 969 case Person(name, age) => age}
trait Person { def name: String def age: Int}
object Person { def unapply(person: Person): Option[(String, Int)] = Some((person.name, age))}
somePerson match { case Person(“Moses”, _) => 969 case Person(name, age) => age}
Case Classes
No need for val in parameters
case class Villain( val name: String, val archenemy: SuperHero) extends Character
No need for val in parameters
case class Villain( val name: String, val archenemy: SuperHero) extends Character
No need for new keyword
new Villain(“Mandarin”, tonyStark)
object Villain { def apply(name: String, archenemy: SuperHero) = new Villain(name, archenemy)}
No need for new keyword
new Villain(“Mandarin”, tonyStark)
object Villain { def apply(name: String, archenemy: SuperHero) = new Villain(name, archenemy)}
No need for new keyword
new Villain(“Mandarin”, tonyStark)
object Villain { def apply(name: String, archenemy: SuperHero) = new Villain(name, archenemy)}
equals and hashCodeval mandarin = Villain(“Mandarin”, tonyStark)
mandarin == Villain(“Mandarin”, tonyStark)
val villainRank = Map(mandarin -> 81)
Intuitive toString
TonyStark.toString == “Civilian(Tony Stark,Fortune)”
Handy copy method
val batman = SuperHero(“Batman”, List(Genius, Gadgets), Civilian(“Bruce Wayne”, Fortune))
val sixPack = batman.copy(powers = Nil)
…and pattern matching
How the heck ispattern matching done
for case classes?
Sealed classes
sealed trait Wealth
case class Cash(n: Int) extends Wealth
case object Fortune extends Wealth
Any questions?
Next meetup May 28, 2013Java 8• How does it compare to
Scala?• A closer look at λ-
expressions implementation• Influences on future
Scala versions, benefits for Scala developers
Scala 2.10• String Interpolation• Value Classes• Implicit Classes• Macros
Next coding dojo–May 14, 2013