2
votes

I wrote an Akka base-actor that can handle some common messages. I want to reuse this basic behavior in a sub-actor, by extending the base-actor (not by composition of the base-actor).

I have seen several approaches in previous questions. They are all valid but also may be improved:

How extend behaviour of super actor in akka

and

How do I best share behavior among Akka actors?

To make the implementation cleaner, I am trying to achieve the following:

  • When defining the sub-actor, I try to extend only the base-actor (not both Actor and sub-actor). However, I was not able to force the compiler to do this.
  • I also try to not rename the receive partial function, because it is a kind of convention.

Here is a sample of my implementation:

//This is the base-actor that implements the common behavior

trait BetterActor extends Actor {

  abstract override def receive = {
    super.receive orElse { case _ => println("Missing pattern!") }
  }
}

//This is the actor that implements the additional behavior.
//I actually wanted to extend BetterActor. It was not possible.

class MyActor extends Actor {

  def receive = {
    case i: Int =>
      println(s"Yay!!! Got $i")
  }
}

Here are two alternative ways how I can create an instance of the sub-actor, which combines both the common and the additional behaviors:

//1.

val myBetterActor = system.actorOf(Props(new MyActor with BetterActor), "myBetterActor")

//2.

class MyBetterActor extends MyActor with BetterActor
val myBetterActor = system.actorOf(Props[MyBetterActor], "myBetterActor")

Finally, I may invoke the sub-actor by:

myBetterActor ! 2
myBetterActor ! "a"

Problems with my implementation:

When I create an instance of the sub-actor, only then I can mix in the base-actor, either directly (1) or by defining a new class that mixes in the base-actor.

Like I said before, I would prefer to mix in the base-actor when I define the sub-actor. Not when I try to create an instance of the sub-actor.

P.S. It's fascinating that the designers of this framework did not see it necessary to make this common requirement easy to accomplish.

1
Designers of this framework have created the unhandled method in Actor - it may be enough for you to simply override itghik
@ghik I don't understand your one-liner.rapt

1 Answers

1
votes

i suppose as long as you're not trying to override behavior with BetterActor, you could try something like this:

trait BetterActor extends Actor {
  override def unhandled(message: Any): Unit = message match {
    case e: CommonMessage => println("COMMON!")
    case e => super.unhandled(e)
  }
}

class MyActor extends BetterActor {
  override def receive = {
    case i: Int => println(s"Yay!!! Got $i")
  }
}