#914 Global Fields

kaushik Fri 15 Jan 2010

Fan's static fields has to be a constant. What are the other alternatives to store a global state?

In my case, If I want to store a closure between web requests where should I put it in? Putting it in session does not work because, its not serializable.

brian Fri 15 Jan 2010

There is no global state in the traditional sense because that would require synchronization. Instead what you do is use an Actor who manages that state and other actors send it messages to access/change the state.

tactics Fri 15 Jan 2010

If you want to go to bad programmer hell, there's the Unsafe class to bypass the type systems const requirements. But you're better off looking for a more Fantomy solution.

kaushik Fri 15 Jan 2010

ok,

But still there is rule that the messages passed to actors should be serializable.. I created the following example to store a closure in an actor against a name and later get it back, can you tell me what's wrong with the code below.. I get the following error sys::IOErr: Not serializable: |sys::Obj->sys::Void|

pool := ActorPool()
closureActor := Actor(pool) |msg|
{
  Obj[] lst := (Obj[])msg

  //Get the action and see if we are storing or getting a closure
  Str action := lst[0]

  if(action == "put"){//store a closure
    Str name := lst[1] //Type name against which the clsoure should be stored
    closure := (|Obj|)lst[2]

    closureMap := (Str:|Obj|)Actor.locals.get("closureMap", Str:|Obj|[:])
    closureMap[name] = closure
    return closure
  }
  else if(action == "get"){//Get the closure back
     Str name := lst[1] //Type name against which we store the closure earlier
     closureMap := (Str:|Obj|)Actor.locals.get("closureMap", Str:|Obj|[:])
     return closureMap[name]
  }

  return "Something else"
}

test := |Obj x|{
    echo("hello")
}

closureActor.send(Obj["put", "closure1", test])
closure := (|Obj|)closureActor.send(Obj["get", "closure1"]).get
closure(Obj())

brian Fri 15 Jan 2010

You can't pass a mutable data structure b/w actors because then that would then expose race conditions.

So what you pass between actors must also be with immutable (const or immutable collection) or serializable.

In your case, functions can be immutable but only if certain rules apply - see Immutable Functions.

KevinKelley Fri 15 Jan 2010

Interesting... I had to try to figure out what you were doing, so I tried your code. First thing that happens is, the closure test you're saving reports itself as immutable, okay, but the list you're passing it in (to the closureActor.send ) doesn't. So, calling toImmutable on that list makes the send happen okay.

Next problem is the map that you're getting from the Actor.locals: you're giving a default, empty map, so since there isn't a closureMap already stored, you get the new empty default one. But you're not saving it back into the Actor.locals, so later (in the "get" response) you just get an empty map again.

Anyway, with those two tweaks, your example works.

Login or Signup to reply.