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.
Try it the other way around:
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).
BTW, you can read more about the pattern (not related to Actors) here.
There's a simple and concise solution:
Define a Receiving trait that chains multiple receive functions using
orElse
:Using this in actors is easy:
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):
Then the behaviors you want to be able to compose into actors:
And lastly, an actual actor that uses these composable behaviors:
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
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:
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
we have receive's method chain
1)
2)
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