0

For example, I have

trait Logger { 
  def log(m: Message) = ??? 
}

If I want to pass a Logger as parameter I would simple call def foo(l: Logger).

But if I have

trait Logger { 
  def log(m: Message) = ??? 
  def receive = {
    case m: Message = log(m)
  }
}

,I must pass an ActorRef to be able to call !/? etc on it. But that completely breaks type safety - def log(ar: ActorRef), and nothing says that it should be an Logger underneath.

So, in the end I'd like to call

class Foo(logger: Logger) {
  def foo(m: Message) = logger ! message
}
dveim
  • 3,381
  • 2
  • 21
  • 31

2 Answers2

4

Well, yes. That's just how Akka works, because actors can change behavior. See How to restrict actor messages to specific types?.

Solution 1: define a wrapper class like

case class LoggerActor(ar: ActorRef) {
  def log(m: Message) = ar ! m
}

And then use LoggerActor where you want to make sure you have a Logger. Of course, if you want to do it everywhere, you'll probably want to automate creation of these classes somehow.

Solution 2: Use Akka Typed. Note it's experimental. I won't copy the documentation from there.

Solution 3: Use Scalaz actors instead, which were typed from the beginning. See https://github.com/scalaz/scalaz/blob/series/7.3.x/tests/src/test/scala/scalaz/concurrent/ActorTest.scala for usage examples. For your case it could be

val logger = new Logger { ... }
val loggerActor = new Actor[Message](logger.log)
Alexey Romanov
  • 167,066
  • 35
  • 309
  • 487
-1

You can specify that your ActorRef should implement Logger too:

def log(ar: ActorRef with Logger)
jopasserat
  • 5,721
  • 4
  • 31
  • 50
  • I'm still not sure to understand your porblem... Can't you apply the same thing I state in my answer to this logger that comes as a parameter to your class Foo? `class Foo(logger: ActorRef with Logger)`?? – jopasserat Dec 27 '15 at 17:12
  • Then `logger: ActorRef with Logger` would get method `log`, but it won't use `Logger`'s `receive`. So `logger ! message` would do nothing. – dveim Dec 27 '15 at 17:16
  • This answer will not work. User code never extends `ActorRef`. – Ryan Dec 28 '15 at 02:18
  • was suggesting for him to do so. but the wrapper or Scalaz version looks better – jopasserat Dec 28 '15 at 11:59
  • There's no way to extend `ActorRef` in a way that makes sense. – Ryan Dec 28 '15 at 17:09