tags:

views:

183

answers:

4

I've implemented a Listenable/Listener trait that can be added to Actors. I'm wondering if it's possible to attach this style of trait to an actor without it having to explicitly call the listenerHandler method?

Also I was expecting to find this functionality in the Akka library. Am I missing something or is there some reason that Akka would not not include this?

trait Listenable { this: Actor =>
    private var listeners: List[Actor] = Nil

    protected def listenerHandler: PartialFunction[Any, Unit] = {
        case AddListener(who) => listeners = who :: listeners
    }

    protected def notifyListeners(event: Any) = {
        listeners.foreach(_.send(event))
    }
}

class SomeActor extends Actor with Listenable
{
    def receive = listenerHandler orElse {
        case Start => notifyListeners(Started())
        case Stop => notifyListeners(Stopped())
    }
}
+4  A: 

Why not extend Actor directly, or if you want non-Actors to be Listenable also, create a ListenableActor that extends Actor with Listenable?

You then would override receive in Actor as you've done above (except you'd want to call super.receive also, wouldn't you?--you'd just want to modify the function that's passed in).

Rex Kerr
Well this is the thing, in both situations I would have to remember to call either super.receive or *listenerHanlder*. I was wondering if there was a mechanism in Scala in general or any of the Actor libraries that allowed the actor implementing Listenable to not have to do anything except say: *with Listenable*
Brian Heylin
But you'd only have to say `extends ListenableActor` instead of `extends Actor`; inside `ListenableActor` you'd have already overridden `receive` (and, presumably, `receiveWithin`). See also Daniel's answer.
Rex Kerr
+2  A: 

I suggest you extend Actor and use an abstract override.

Daniel
A: 

Here is a solution (a modified version of the example from Beginning Scala):

import se.scalablesolutions.akka.actor.Actor

case class AddListener(who: Actor)
case class RemoveListener(who: Actor)

class ListenableActor extends Actor {
    private var listeners: List[Actor] = Nil

    def receive = {
        case AddListener(who) => listeners ::= who
        case RemoveListener(who) => listeners.filter(_ ne who)
    }

    protected def notifyListeners(event: Any) = {
        listeners.foreach(_.send(event))
    }
}

class ImplementingActor extends ListenableActor {
    override def receive = {
        super.receive orElse {
            case Message(content) => println(content)
        }
    }
}
Brian Heylin
+2  A: 

Why haven't I seen this question before, erm, well, better late than never:

http://github.com/jboner/akka/blob/master/akka-core/src/main/scala/routing/Listeners.scala

Viktor Klang
Thanks Viktor, I think I asked this question just as the class was added to the Akka repo.
Brian Heylin