Reading Time: 2 minutes

A partial function is defined as

trait PartialFunction[-A, +B] extends (A) ⇒ B

It is a unary function which defines a domain. Not all values of A would be a part of the domain. For instance, in the following code block

val sample = 1 to 10 val isEven: PartialFunction[Int, String] = { case x if x % 2 == 0 => x+" is even" }

The odd values of A would not match the domain. We can check this by the abstract method isDefined which is available for partial functions.

abstract def isDefinedAt(x: A): Boolean

isEven.isDefinedAt(12) //> res0: Boolean = true isEven.isDefinedAt(11) //> res1: Boolean = false

Hence the above defined partial function would match for even values and not for the odd values. Something like the following calls would result in the expected output

isEven(12) //> res2: String = 12 is even isEven(11) //> scala.MatchError: 11 (of class java.lang.Integer)

Interestingly, PartialFunction offers a method called orElse which allows us to combine domains.

Hence, in the above scenario, if we have an alternate isOdd PartialFunction defined like this

val isOdd: PartialFunction[Int, String] = { case x if x % 2 == 1 => x + " is odd" }

Then we can combine the 2 domains together with an orElse to get something like this

val numbers = (1 to 10) map (isEven orElse isOdd) //> numbers : scala.collection.immutable.IndexedSeq[String] = Vector(1 is odd, //| 2 is even, 3 is odd, 4 is even, 5 is odd, 6 is even, 7 is odd, 8 is even, 9 //| is odd, 10 is even)

Ok, so far so good. Now how do we take it to the actors. Simple, the Actor.Receive is a PartialFunction.

type Receive = PartialFunction[Any, Unit]

So let us assume that we want to modularize code now on the basis of infrastructure events and our application events.

So say we define one receive block like this

def eventSourceReceive: Actor.Receive = { case RegisterListener(listener) => listeners = listeners :+ listener case UnregisterListener(listener) => listeners = listeners filter { _ != listener } }

and another one like this

def monitorReceive: Receive = { // Our rate of climb has changed case RateChange(amount) => rateOfClimb = amount.min(1.0f).max(-1.0f) * maxRateOfClimb // Calculate a new heartRate case Tick => val tick = System.currentTimeMillis heartRate = heartRate + ((tick - lastTick) / 60000.0) * rateOfClimb lastTick = tick sendEvent(MonitorUpdate(heartRate)) }

and now we combine the 2 domains so that our actor is able to deal with both kinds of incoming events

def receive = eventSourceReceive orElse monitorReceive

This way, we would be able to keep our receive blocks modularized and still be able to handle all the messages by combining the domains together.