#1158 Unable to initialize Actor.locals in a constructor

katox Thu 22 Jul 2010

I found out that Actor.locals can't be set in Actor's constructor. An example:

using concurrent

class Actors
{

  Void main()
  {
    counterActor
  }

  Void counterActor()
  {
    echo("\n--- echoCounter ---")

    a := Actor(ActorPool()) |msg|
    {
      if (msg == "current") return Actor.locals["counter"]
      if (msg == "reset") { Actor.locals["counter"] = 0; return null }
      Actor.locals["counter"] = 1 + Actor.locals["counter"]
      return null  // ignored
    }

    //a.send("reset") // Result null if commented out (line 23)

    a.send(1)
    a.send(2)
    a.send(3)

    echo("Result " + a.send("current").get)
  }
}

const class CounterActor : Actor
{
  new make(ActorPool p) : super(p)
  {
    Actor.locals["counter"] = 0
  }

  override Obj? receive(Obj? msg) 
  {
      echo("msg=$msg")
      if (msg == "current") return Actor.locals["counter"]
      if (msg == "reset") { Actor.locals["counter"] = 0; return null }
      Actor.locals["counter"] = 1 + Actor.locals["counter"]
      return null  // ignored
  }
}

If "reset" is sent to the actor everything is fine. If the line is commented out counter will be null despite constructor initialization. I wonder what is the reason for that but if it is intentional I think it should be noted in docs (or an compilation error).

brian Thu 22 Jul 2010

Remember that the Actor's constructor runs in the launching thread, not on the actor's thread. So setting a local in the ctor sets it in the wrong thread. Anything that you want to initialize has be done by sending your actor a message (or initializing the actor's const fields).

A typical pattern I use is something like this:

Obj? receive(Obj? msg)
{
  state := Actor.locals["state"]
  if (state == null) Actor.locals["state"] = state = initState
  return dispatch(state, msg)
}

Login or Signup to reply.