src091
src091

Reputation: 2847

Referencing external val in actor class

Is it prohibited by design or am I doing something wrong?

val ext = 1

class Test extends Actor {
  def receive = { case _ => println(ext) }
}

try {
  val sys = ActorSystem("lol")
  sys.actorOf(Props[Test], "test") ! true
} catch {
  case e: Throwable => println(e)
}  

once I send a message to Test I get an exception java.lang.IllegalArgumentException: no matching constructor found on class HelloAkkaScala$Test$1 for arguments [].
I don't have this exception if I don't reference ext inside of Test class.
I'm using Akka 2.3.4

Upvotes: 0

Views: 91

Answers (1)

Eugene Loy
Eugene Loy

Reputation: 12446

There is nothing wrong in accessing val (not var or any other mutable state) defined outside of the actor.

Just tried to run your example code in Akka 2.3.5 and it works fine. You probably have a typo somwhere in your original code.

UPDATE

Looking closer at the error you are getting it seems like you've defined Test class inside some other class.

In this case inner class (Test) will receive reference to outer class behind the scenes in order to be able to close on it's members (ext).

This also means that constructor of the inner class will take reference to the outer class (syntactic sugar hides this).

This also explains why you are getting the error (you pass 0 args to constructor but there actually some hidden ones that you are not supplying).

Here is the example that reproduces this:

class Boot {

  val ext = 1

  class Test extends Actor {
    def receive = { case _ => println(ext) }
  }

  try {
    val sys = ActorSystem("lol")
    sys.actorOf(Props[Test], "test") ! true
  } catch {
    case e: Throwable => println(e)
  }

}

object Boot extends App {

  new Boot

}

... and here is a quick workaround (in this case I make Test and ext "static" by moving them to companion object, but you can achieve similar results by referencing ext as a member of some other instance, passed to constructor):

class Boot {

  import Boot.Test

  try {
    val sys = ActorSystem("lol")
    sys.actorOf(Props[Test], "test") ! true
  } catch {
    case e: Throwable => println(e)
  }

}

object Boot extends App {

  val ext = 1

  class Test extends Actor {
    def receive = { case _ => println(ext) }
  }

  new Boot

}

Upvotes: 2

Related Questions