- obj match {
- case "Val" => // do something
- case _ => // handle all other cases
- }
It is intuitive and obvious how to share the code of the right hand side if the case statement by factoring that code out to a method. But would it not be useful to be able to factor out an entire case statement (PartialFunction) and later chain them together as needed?
This is indeed possible and very easy to do:
- /*
- We need to declare Partial Functions so to add brevity I am adding this alias
- */
- scala> import scala.{PartialFunction => PF}
- import scala.{PartialFunction=>PF}
- /*
- You have to explicitly declare the type because the type inferencer cannot know what type of PartialFunction to create
-
- A PartialFunction is Strictly type so some functions can only be used on Ints for example
- */
- scala> val i : PF[Any, Unit] = {case x:Int => println("int found")}
- i: PartialFunction[Any,Unit] = < function1>
- scala> val j : PF[Any, Unit] = {case x:Double => println("Double found")}
- j: PartialFunction[Any,Unit] = < function1>
- scala> val * : PF[Any, Unit] = {case x=> println("Something else found")}
- *: PartialFunction[Any,Unit] = < function1>
- /*
- one might think that you can do:
- 1 match (i orElse j orElse *)
- but in fact (i orElse j orElse *) forms a PartialFunction not a pattern so cannot be used with match. Instead it must be used as a function
- */
- scala> (i orElse j orElse *)(1)
- int found
- scala> (i orElse j orElse *)(1.0)
- Double found
- scala> (i orElse j orElse *)(true)
- Something else found
- /*
- for specific cases it is possible to chain the an anonymous partial function with the common function
- This is not so nice so it is probably best to declare a val instead of inline like this
- */
- scala> (({case s:String => println("String found")}:PF[Any,Unit]) orElse j orElse *)("hello")
- String found
For another example of chaining PartialFunctions the Akka tutorial has a good example in the ChatServer trait: http://jonasboner.com/2010/01/04/introducing-akka.html
A nice bit of sugar that was being added to 2.8 is to define a type alias in Predef for PartialFunction
ReplyDeletetype =>?[-A, +B] = PartialFunction[A, B]
then you could say:
val i : Any =>? Unit = {case x:Int => println("int found")}
which reads a little nicer I think. I am not sure if they are going to keep it or not.
for the last example you can also make it a bit terser if you define:
def =>?[A, B](id : A =>? B) = id
(=>?[Any, Unit]{case s : String => println("String found")} orElse =>?[Any, Unit]{case i : Int => println("Int found")})("Hi")
good tip. I think that warrants a post
ReplyDeleteSorry, too much red :-(
ReplyDeleteis it just me or is this the most beautiful and elegant thing ever?
ReplyDeleteAnd @Ben Jackman's shorthand makes it every cooler!
ReplyDelete