Mandroid
Mandroid

Reputation: 7504

receive method in Akka actor

I have following implementation for receive method in Akka actor implementation.

override def receive: Receive = {
  case SetRequest(key, value) =>{
    log.info("Received SetRequest - key:{} ,value:{}", key,value)
    map.put(key,value)
    sender() ! Status.Success
  }
  case GetRequest(key) => {
    log.info("Received GetRequest for - key:{}", key)
    val response: Option[Object] = map.get(key)
    response match {
      case Some(x) => sender() ! x
      case None => sender() ! Status.Failure(new KeyNotFoundException(key))
    }
  }
  case o => Status.Failure(new ClassNotFoundException())
}

I have few queries here.

In Actor.scala, receive is defined as:

def receive: Actor.Receive

Actor.Receive is:

type Receive = scala.PartialFunction[scala.Any, scala.Unit]

So how does my code in receive conforms to Actor.Receive?

Second, what is this style of pattern matching?receive seems to receive no argument, so what am I actually trying to match?For eg., in code I match response,which makes sense as response is calculated before it is pattern matched.

Upvotes: 0

Views: 1461

Answers (2)

Leo C
Leo C

Reputation: 22449

So how does my code in receive conforms to Actor.Receive? ... What is this style of pattern matching?

In Scala, case is a common kind of partial functions. For example:

val oneOrTwo: PartialFunction[Int, String] = {
  case 1 => "one"
  case 2 => "two"
}
// oneOrTwo: PartialFunction[Int,String] = <function1>

val reciprocal: PartialFunction[Double, Double] = { case i if i != 0 => 1 / i }
// reciprocal: PartialFunction[Double,Double] = <function1>

Hence case partial functions can be used to implement receive which has the PartialFunction[Any, Unit] signature.

The Any argument type allows you to use case to check against an input of any kind you wish (e.g. SetRequest(key, value), GetRequest(key) in your sample code).

On the return type, Unit allows you to put in any message processing code (e.g. sender() ! Status.Success, response match {...} in your sample code) and does not demand a return value.

receive seems to receive no argument, so what am I actually trying to match?

Your class extends Actor, so when overriding receive, you need to implement the method declared in trait Actor (see below, from Akka source code) which you already did with your case partial function.

object Actor {
  type Receive = PartialFunction[Any, Unit]
  // ...
}

trait Actor {
  def receive: Actor.Receive
  // ...
}

By extending Actor and implementing method receive, Akka equips your class with all the message-driven actor features including a mailbox and designates a dispatcher to feed any messages sent to it (e.g. myActor ! GetRequest(key) from another actor) as input to the receive method.

Upvotes: 2

Johnneh
Johnneh

Reputation: 317

A partial function comes from mathematics and is opposed to a total function. A total function is defined for all inputs like this one:

val f = (i: Int) => i + 10

Function f produces a valid result for any input of type Int. However this partial function:

val g = (i: Int) => 10/i

does not (zero would result in an error).

In Scala you can create these special functions like so:

val h: PartialFunction[Int, Int] = {
  case i: Int if i != 0 => 10/i
}

It has a methdod isDefinedAt which can be used to check if it produce a valid result for a given input:

h.isDefinedAt(0) // false
h.isDefinedAt(5) // true

You can call partial functions like normal functions:

h(5)

But they also allow you to chain and combine them like regular functions with orElse. Example:

val x: PartialFunction[Int, String] = {
  case i: Int if i = 10 => "ten"
}

val y: PartialFunction[Int, String] = {
  case i: Int if i = 5 => five"
}

val z = y orElse x

z(10) // "ten"
z(5)  // "five"
z(0)  // MatchError

Alone they are able to handle one case each, combined they can handle two.

To your second question: receive is an unimplemented method in the Actor trait. It will be called somewhere in the Akka implementation with your message. It returns a partial function so it can be combined with the default Akka messages like PoisonPill and so on.

Upvotes: 0

Related Questions