I'm trying to implement a Pub/Sub trait to mix into other akka actors using a stackable trait.
Here is what I came up with:
trait PubSubActor extends Actor {
abstract override def receive =
super.receive orElse {
case Subscribe(topic) => /* ... */
case Publish(topic, msg) => /* ... */
}
}
class MyActor extends Actor with PubSubActor {
override def receive = {
case SomeMessage(a, b, c) => /* ... */
}
}
At which point, the compiler throws back an error:
error: overriding method receive in trait MyActor... method receive needs `abstract override' modifiers.
Can you explain to me why this isn't working? How can I fix it so it works?
Thanks!
UPDATE
The following works:
trait PubSubActor extends Actor {
abstract override def receive =
super.receive orElse {
case Subscribe(topic) => /* ... */
case Publish(topic, msg) => /* ... */
}
}
class MyActor extends Actor {
override def receive = {
case SomeMessage(a, b, c) => /* ... */
}
}
class MyActorImpl extends MyActor with PubSubActor
But why? Why can I get the behavior I want this way but not the other? Any reasons? I can't seem to figure out the underlying difference between these two samples that makes the difference.
There's a simple and concise solution:
Define a Receiving trait that chains multiple receive functions using orElse :
trait Receiving {
var receivers: Receive = Actor.emptyBehavior
def receiver(next: Actor.Receive) { receivers = receivers orElse next }
def receive = receivers // Actor.receive definition
}
Using this in actors is easy:
trait PubSubActor extends Receiving {
receiver {
case Publish => /* I'm the first to handle messages */
}
}
class MyActor extends PubSubActor with Receiving {
receiver {
case SomeMessage => /* PubSubActor didn't handle, I receive the message */
}
}
First PubSubActor's receive will be called. If message wasn't handled it will be passed to MyActor's receive.
You can certainly achieve what you are looking for using Akka's composable actor feature. This is described a bit in Extending Actors using PartialFunction chaining.
First, the infrastructure code (straight from the docs):
class PartialFunctionBuilder[A, B] {
import scala.collection.immutable.Vector
// Abbreviate to make code fit
type PF = PartialFunction[A, B]
private var pfsOption: Option[Vector[PF]] = Some(Vector.empty)
private def mapPfs[C](f: Vector[PF] => (Option[Vector[PF]], C)): C = {
pfsOption.fold(throw new IllegalStateException("Already built"))(f) match {
case (newPfsOption, result) => {
pfsOption = newPfsOption
result
}
}
}
def +=(pf: PF): Unit =
mapPfs { case pfs => (Some(pfs :+ pf), ()) }
def result(): PF =
mapPfs { case pfs => (None, pfs.foldLeft[PF](Map.empty) { _ orElse _ }) }
}
trait ComposableActor extends Actor {
protected lazy val receiveBuilder = new PartialFunctionBuilder[Any, Unit]
final def receive = receiveBuilder.result()
}
Then the behaviors you want to be able to compose into actors:
trait PubSubActor { self:ComposableActor =>
receiveBuilder += {
case Subscribe(topic) => /* ... */
case Publish(topic, msg) => /* ... */
}
}
trait MyActor { self:ComposableActor =>
receiveBuilder += {
case SomeMessage(a, b, c) => /* ... */
}
}
And lastly, an actual actor that uses these composable behaviors:
class MyActorImpl extends ComposableActor with PubSubActor with MyActor
Try it the other way around:
object Subscription {
case object Subscribe
case object Unsubscribe
}
trait Subscription {
this: Actor =>
import Subscription._
var subscribers = Set.empty[ActorRef]
def receive: Receive = {
case Subscribe => subscribers += sender
case Unsubscribe => subscribers -= sender
}
}
class MyActor extends Actor with Subscription {
def receive = super.receive orElse {
case msg => // handle msg
}
}
Note that this still makes use of the stackable trait pattern, which is hidden by the fact that I've omitted the core. So something like this would still work (at least I think I will, ATM I have no time to check if it compiles).
class Core extends Actor {
def receive = Actor.emptyBehavior
}
class MyActor extends Core with Subscription
BTW, you can read more about the pattern (not related to Actors) here.
For the first, excuse me for my English
I think the point is that abstract override modifier requires presence of concrete implementation of receive method but in the first construction
class MyActor extends Actor with PubSubActor {
override def receive = {
case SomeMessage(a, b, c) => /* ... */
}}
it is not done
The reason is that scala compiler makes linearization for inheritance
so in receive's method chain we have the following sequence:
1) override def receive = {
case SomeMessage(a, b, c) => /* ... */
}
2) abstract override def receive = super.receive orElse {
case Subscribe(topic) => /* ... */
case Publish(topic, msg) => /* ... */
}
3) then Actor.receive - it hasn't an implementation
So PubSubActor.receive cannot be called because it use super.receive,
in its turn super.receive relies on Actor.receive, but Actor.receive hasn't an implementation.
In the second construction
class MyActor extends Actor {
override def receive = {
case SomeMessage(a, b, c) => /* ... */
}}
class MyActorImpl extends MyActor with PubSubActor
we have receive's method chain
1)
abstract override def receive = super.receive orElse {
case Subscribe(topic) => /* ... */
case Publish(topic, msg) => /* ... */
}
2)
override def receive = {
case SomeMessage(a, b, c) => /* ... */
}
3) then Actor.receive - it hasn't an implementation
So PubSubActor.receive can successfully call super.receive
Additional info:
Stackable traits
Scala language specification, see 5.1.2
Related
Say I have the below:
type Receive = PartialFunction[Any, Unit]
trait Functionality {
/**
* A set containing all Receive functions
*/
var allReceives: Set[Receive] = Set[Receive]()
}
Now other trait's can extend Functionality and do awesome stuff. Example:
trait LoadBalancer extends Functionality{
def body:Receive = {
case ...
}
allReceives += body
}
And ultimately my class:
class Main with LoadBalancer with SecurityFunctionality
with OtherFunctionality with Functionality{
def receive = {
case x if allReceives.foldLeft(false) { (z, f) => if (f isDefinedAt x) { f(x); true } else z } == true => ()
}
def body: Receive = {
}
allReceives += body
}
Question: What I wish to do is, in Main I need to call body function of all the traits that I have inherited. This way my code can be loosely coupled and I can add/remove functionality at a go.
The above works, but I do not like it as the compiler cannot guarantee that any trait that extends Functionality should add its body to allReceives.
I cannot declare def body:Receive in Functionality as then my implementation in Main will override body implementations of other traits. I am sure there should be a smarter way!
On second thought, composition really might be a better option here. This is a simpler solution, without any funny "abstract override"s:
object Main {
type Receive = PartialFunction[Any, Unit]
trait Receiver {
def receive: Receive
}
class LoadBalancer extends Receiver {
override def receive: Receive = {
case "one" => println("LoadBalancer received one")
}
}
class OtherFunctionality extends Receiver {
override def receive: Receive = {
case "two" => println("OtherFunctionality received two")
}
}
class MainFunctionality extends Receiver {
override def receive: Receive = {
case "three" => println("MainFunctionality received three")
}
}
class CompositeReceiver(receivers: List[Receiver]) extends Receiver {
override def receive: Receive = {
case msg =>
receivers.find(_.receive.isDefinedAt(msg)) map (_.receive(msg))
}
}
def main(args: Array[String]) {
val main = new CompositeReceiver(List(new OtherFunctionality, new LoadBalancer, new MainFunctionality))
main.receive("one")
main.receive("two")
main.receive("three")
}
}
This does not really answer your question, but here is a solution using the stackable traits pattern. Alas you still need to call super.receive as the last case in each trait, but I could not find a way around that yet.
object Main {
type Receive = PartialFunction[Any, Unit]
trait Receiver {
def receive: Receive
}
trait LoadBalancer extends Receiver {
abstract override def receive: Receive = {
case "one" => println("LoadBalancer received one")
case msg => super.receive(msg)
}
}
trait OtherFunctionality extends Receiver {
abstract override def receive: Receive = {
case "two" => println("OtherFunctionality received two")
case msg => super.receive(msg)
}
}
class Main extends Receiver {
override def receive: Receive = {
case "three" => println("Main received three")
}
}
def main(args: Array[String]) {
val main = new Main with OtherFunctionality with LoadBalancer
main.receive("one")
main.receive("two")
main.receive("three")
}
}
I'm creating multiple traits which extend Actor. Then I want to create an actor class which uses some of these traits. However, I'm not sure how to combine the receive methods from all traits in the receive method of the Actor class.
Traits:
trait ServerLocatorTrait extends Actor {
def receive() = {
case "s" => println("I'm server ")
}
}
trait ServiceRegistrationTrait extends Actor {
def receive() = {
case "r" => println("I'm registration ")
}
}
The Actor:
class FinalActor extends Actor with ServiceRegistrationTrait with ServerLocatorTrait {
override def receive = {
super.receive orElse ??? <--- what to put here
}
}
Now if I send "r" and "s" to FinalActor it goes only in ServerLocatorTrait - which is the last trait added.
So the way this works right now is that it considers super the last trait added, so in this case ServerLocatorTrait
Question:
How do I combine the receive methods from all the traits in FinalActor?
PS - I've seen the actors with react example: http://www.kotancode.com/2011/07/19/traits-multiple-inheritance-and-actors-in-scala/
but it's not what I need
I'm not sure if you can combine the receive methods, since that would involve calling the super's super to obtain the ServiceRegistration's receive method. It would also be very confusing.
Another way would be to give different names to the receive method in the traits.
trait ServerLocatorTrait extends Actor {
def handleLocation: Receive = {
case "s" => println("I'm server ")
}
}
trait ServiceRegistrationTrait extends Actor {
def handleRegistration: Receive = {
case "r" => println("I'm registration ")
}
}
class FinalActor extends Actor with ServiceRegistrationTrait with ServerLocatorTrait {
def receive = handleLocation orElse handleRegistration
}
object Main extends App {
val sys = ActorSystem()
val actor = sys.actorOf(Props(new FinalActor))
actor ! "s"
actor ! "r"
sys.shutdown()
}
You can still use you initial approach, but you must chain the super.receive for each mixed trait.
trait IgnoreAll extends Actor {
def receive: Receive = Map()
}
trait ServerLocatorTrait extends Actor {
abstract override def receive = ({
case "s" => println("I'm server ")
}: Receive) orElse super.receive
}
trait ServiceRegistrationTrait extends Actor {
abstract override def receive = ({
case "r" => println("I'm registration ")
}: Receive) orElse super.receive
}
class FinalActor extends IgnoreAll with ServiceRegistrationTrait with ServerLocatorTrait
The latter solution looks pretty ugly to me.
Please see the below link for a more detailed discussion on the subject:
Extending Actors using PartialFunction chaining
I'm using the Akka actors library here. The actors library defines a partial function "receive" which an actor that extends "actor" must implement to deal with various messages. I am creating a trait hierarchy for my application where trait "clockActor" extends Actor and "MasterClock" and "SubClock" extend "clockActor". I'm looking to add the common functionality of clocks in to the "clock" trait's receive function but then how to I add extra functionality to the receive function in the master and sub clock traits?
In short, I need a way to add extra case statements to a partial function.
Ideas?
As already suggested, you could easily compose PartialFunctions using orElse
trait ClockActor {
def commonOp = {
case ... => ...
}
}
class MasterClock extends Actor with ClockActor {
def receive = commonOp orElse masterOp
def masterOp = {
case ... => ...
}
}
class SubClock extends Actor with ClockActor {
def receive = commonOp orElse subOp
def subOp = {
case ... => ...
}
}
One thing that comes to mind is to do something like this:
trait ClockActor {
def pf:PartialFunction[String, Boolean] = {
case "a" => true
case v if(_pf.isDefinedAt(v)) => _pf.apply(v)
}
def _pf:PartialFunction[String, Boolean] = Map.empty
}
object MasterClock extends ClockActor {
override def _pf:PartialFunction[String, Boolean] = {
case "b" => false
}
println(pf("a"))
println(pf("b"))
}
which will output:
scala> MasterClock
true
false
The value true comes from the definition in the partial function of the Trait ClockActor, the falsecomes from the Object MasterClock.
trait A extends Actor {
private val s = Set[Int]()
override def act() {
loop {
react {
// case code that modifies s
}
}
}
}
trait B extends Actor {
private val t = Set[String]()
override def act() {
loop {
react {
// case code that modifies t
}
}
}
}
val c = new C with A with B //...?
What I really want is some sort of auto-combining of B.act() and C.act(), but with trait mix-ins, only B.act() will be called. Is there an easy way to accomplish this?
EDIT: Here is a half-solution I've found. I say 'half' because the original traits no longer extend Actor, and C with A with B needs to be defined as a class as opposed to dynamic mixing-in. Maybe I should call it a 'quarter-solution'?
Maybe you could make a trait that forwards the message on to a list of other Actors, so that you don't have to modify A or B:
trait C extends Actor {
private val acts: Seq[Actor] = Seq(new A{}, new B{})
override def act() {
acts foreach (_.start)
loop {
react { case x => acts foreach { _ ! x } }
}
}
}
You could of course leave acts abstract or override it with a different set when you instantiate this.
Extending the Actor class:
import actors.Actor
class MixableActor extends Actor {
protected var acts = List[PartialFunction[Any, Unit]]()
final override def act() {
loop {
react {
acts.reduce((a, b) => a orElse b)
}
}
}
final def receive(act: PartialFunction[Any, Unit]) {
acts = act :: acts
}
}
Sample Code:
abstract class Node extends MixableActor {
...
}
trait User extends MixableActor {
val files = scala.collection.mutable.Set[Data]()
}
trait Provider extends User {
receive({
case ("provide", file: Data) =>
provide(file)
}: PartialFunction[Any, Unit])
}
trait Consumer extends User {
receive({
case ("consume", file: Data) =>
consume(file)
}: PartialFunction[Any, Unit])
}
Sample Usage:
val provider = new Node with Provider
val consumer = new Node with Consumer
val provider_and_consumer = new Node with Provider with Consumer
Consider these two traits:
trait Poked extends Actor {
override def receive = {
case Poke(port, x) => ReceivePoke(port, x)
}
def ReceivePoke(port: String, x: Any)
}
trait Peeked extends Actor {
override def receive = {
case Peek(port) => ReceivePeek(port)
}
def ReceivePeek(port: String)
}
Now consider I can create a new Actor that implements both traits:
val peekedpoked = actorRef(new Actor extends Poked with Peeked)
How do I compose the receive handlers? i.e., the receiver should be something like the following code, though "automatically generated" (i.e., all traits should compose):
def receive = (Poked.receive: Receive) orElse (Peeked.receive: Receive) orElse ...
You can use super[T] to reference members of particular super classes/traits.
For example:
trait IntActor extends Actor {
def receive = {
case i: Int => println("Int!")
}
}
trait StringActor extends Actor {
def receive = {
case s: String => println("String!")
}
}
class IntOrString extends Actor with IntActor with StringActor {
override def receive = super[IntActor].receive orElse super[StringActor].receive
}
val a = actorOf[IntOrString].start
a ! 5 //prints Int!
a ! "Hello" //prints String!
Edit:
In response to Hugo's comment, here's a solution that allows you to compose the mixins without having to manually wire their receives together. Essentially it involves a base trait with a mutable List[Receive], and each mixed-in trait calls a method to add its own receive to the list.
trait ComposableActor extends Actor {
private var receives: List[Receive] = List()
protected def registerReceive(receive: Receive) {
receives = receive :: receives
}
def receive = receives reduce {_ orElse _}
}
trait IntActor extends ComposableActor {
registerReceive {
case i: Int => println("Int!")
}
}
trait StringActor extends ComposableActor {
registerReceive {
case s: String => println("String!")
}
}
val a = actorOf(new ComposableActor with IntActor with StringActor).start
a ! 5 //prints Int!
a ! "test" //prints String!
The only thing to keep in mind is that the order of the receives should not be important, since you won't be able to easily predict which one is first in the chain, though you could solve that by using a mutable hashmap instead of a list.
You can use empty Receive in base actor class and chain receives in their definitions.
Sample for Akka 2.0-M2:
import akka.actor.Actor
import akka.actor.Props
import akka.event.Logging
import akka.actor.ActorSystem
class Logger extends Actor {
val log = Logging(context.system, this)
override def receive = new Receive {
def apply(any: Any) = {}
def isDefinedAt(any: Any) = false
}
}
trait Errors extends Logger {
override def receive = super.receive orElse {
case "error" => log.info("received error")
}
}
trait Warns extends Logger {
override def receive = super.receive orElse {
case "warn" => log.info("received warn")
}
}
object Main extends App {
val system = ActorSystem("mysystem")
val actor = system.actorOf(Props(new Logger with Errors with Warns), name = "logger")
actor ! "error"
actor ! "warn"
}