#1374 [idea] static thread-local mutable fields

Akcelisto Fri 7 Jan 2011

I suggest to allow static mutable thread-local fields:

class Context{
  static Context cur
}

If program gets/sets this field from another thread, then Fantom VM throw ConcurrentErr("Concurrent access to mutable static field").

Nowadays I use equivalent workaround:

class Context{
  Context? cur() {
    Actor.locals["context"]
  }
  Void setCur(Context? context){
    Actor.locals["context"] = context
  }
}

Why I do not want this workaround?

  • Clear syntax is better then workaround.
  • This is slightly annoyed.
  • I want to use shortcut = for field set instead of setFieldName.
  • My pods depend on concurrent:: although they do not work with actors.
  • I want to get clear exception when access from another thread instead of null or NullErr.

helium Fri 7 Jan 2011

See also `http://fantom.org/sidewalk/topic/204` and `http://fantom.org/sidewalk/topic/1247`

Akcelisto Fri 7 Jan 2011

I look at #204. This is good except keyword. Why to need special keyword?

qualidafial Fri 7 Jan 2011

@Akcelisto: Because you might also want to have actor-local instance fields. Although it could probably be accomplished just as well with e.g. an ActorLocal class.

Akcelisto Fri 7 Jan 2011

What is actor-local instance field?

Akcelisto Sat 8 Jan 2011

concurrent::Actor and java.lang::Thread are equivalent? One actor creates one thread?

brian Sat 8 Jan 2011

Actors and Thread are not the same. Actors are scheduled onto Thread pools by the runtime. You can read thru some of the concurrent Java code to see how it works.

I think there is general agreement that using Actor.locals kind of sucks. Best solution which has been proposed to date is to add an actorlocal keyword which would work similar to how .NET has a threadlocal attribute. The problem is that we decided to pull concurrency issues out of the core into its own pod. So it would be awkward to have a language keyword that requires something other than sys. This is why I have been hesitant to move forward.

But there might be other solutions too we haven't come up yet. I haven't spent much time thinking of the problem to be honest.

MoOm Sat 8 Jan 2011

Generics could be a way to solve the keyword problem.

Instead of writing actorlocal Int var, we could write ActorLocal<Int> var. The ActorLocal class would be implemented in the concurrent pod, as actors only make sense in this pod.

To make the syntax even better, cast-operators (ala C++) could also be introduced, so ActorLocal<Int> could be implicitely converted into an Int, without having to use something like var.get.

Generics and cast-operators (or conversion operators) would also make the Unsafe class a lot better. Instead of writing Unsafe var, we could write Unsafe<Int> var so we don't loose type-safety and we'll no longer have to do var.get each time we want to access the value.

brian Sat 8 Jan 2011

Yes, perfect case where generics would be very convenient

jodastephen Sat 8 Jan 2011

I believe that you want the oft talked about superclass code generation.

class Foo extends Actor {
  private Int bar
}

Something like the above, where Actor is capable of code generation by examining the subclass, converting what looks like a regular local variable into the relevant actor local variable.

The same would handle Enums at the very least. Plus, Equals/hashCode generation etc.

Akcelisto Sat 8 Jan 2011

I have more questions.

-1-

If I properly understand: thread-local fields dont need for Fantom because few threads used for many actors. Actor-local fields not implemented yet.

Question: What is Actor.locals? It is actor-instance-local or actor-static-local or thread-local? Or something else?

-2-

I need static thread-local field. (I know that design should avoid global mutable but I dont want to pass context in every method.)

Question: What I should use as thread-local static field? java.lang::ThreadLocal? Actor.locals? Is my workaround from 1st post proper?

-3-

Question: Why class actor is const? This is uncomfortable. May be:

  • forbid public and internal fields in class Actor and in his subclasses
  • remove const

tonsky Sat 8 Jan 2011

It’s sad to see how decision of moving Actors out of sys blocks really handy features from being implemented. I’m talking about this one and my proposition about ! (message send) operator #1340. May be it’s a time to reconsider this decision? After all, Actors are essential part of Fantom, aren’t they? What is the point to have poor-integrated, hard-to-use Actors in separate package with it’s own release cycle rather than have good-integrated, easy-to-use Actors updated with the sys?

helium Sat 8 Jan 2011

Last time I asked a similar question brian answered:

I definitely think Actors should for the most part be a library versus a core part of the language (...) Because libraries have a lot more flexibility for versioning, enhancements, replacement implementations, etc. That is one big reason we moved the concurrency stuff out of sys into its own pod. Although I like actors, I think it is too early to say that should the mechanism for concurrency (versus just one in the library's toolkit).

brian Sat 8 Jan 2011

Question: What is Actor.locals? It is actor-instance-local or actor-static-local or thread-local? Or something else?

Actor.locals is a set of name/value pairs guaranteed to be associated with an actor as it is scheduled on/off threads. While the actor is assigned to a thread it essentially the same as a thread local. But once the actor is unassigned from a thread, the locals are stored with the dormant actor.

I need static thread-local field. (I know that design should avoid global mutable but I dont want to pass context in every method.)

Fantom doesn't expose the concept of threads, only actors. So you would use Actor.locals

Question: Why class actor is const?

Because actors move between threads by definition.

rfeldman Tue 11 Jan 2011

A compromise might be to introduce a shorthand that the whole language could use.

For example, instead of focusing on shortcuts for specifically Actor.locals, what about shortcuts relating Map and fields in general?

e.g.

class Context
{
  static Context cur : Actor.locals["context"]
}

Where the above snippet would perhaps compile to the equivalent of the originally-posted cur() and setCur().

Outside of the concurrent pod, this could be useful for example when dealing with property maps - instead of defining constants and then referencing someMap[keyConstant] you could just define foo : someMap[keyConstant] and just reference foo from then on.

qualidafial Tue 11 Jan 2011

If keeping concurrency separate from sys is important, then let's just add a class concurrent::ActorLocal without any compiler magic. The default constructor could take an optional Func for generating the initial value:

class Foo
{
  ActorLocal bar := ActorLocal { Bar() }
}

The initial value Func would have to be immutable to prevent sharing mutable state.

go4 Tue 11 Jan 2011

+1 for qualidafial's ActorLocal.

ahhatem Sun 16 Jan 2011

I think we should add a mutable keyword, something like:

class Context{
  mutable static Context cur
}

I seriously don't think I should learn the fantom concurrency model just to make a mutable static variable... this is overly complex model for something trivial. the mutable/immutable concept is something that must be understood... but the actors aren't... I usually write tons of code that either have nothing to do with concurrency... or use a different model by design to sync.

Just allow the user to bypass the default safe design on his responsibility.... its his app after all... and if the user wants to screw his app he will probably find a way to do it !!! the whole point is to make sure that he knows what he is doing...

helium Sun 16 Jan 2011

A mutable keyword would make it way to easy for the average programmer to fuck things up.

jodastephen Sun 16 Jan 2011

See http://fantom.org/sidewalk/topic/473#c2893 where a concurrent keyword was briefly discussed. I agree that the cost of creating a simple shared map or counter is too high in Fantom.

MoOm Sun 16 Jan 2011

The mutable is not necessary as we already have the Unsafe class for this: it already provides an easy way to have a mutable variable shared between threads. The big problem with Unsafe is that you loose type safety. Generics would be an elegant way to solve this problem imho.

brian Mon 17 Jan 2011

If you have a mutable static variable, then your code almost certainly will be broken in a multi-thread environment. Some languages are crazy about type safety, well Fantom is crazy about guaranteeing that mutable state is not shared between actors.

Although we do have the escape hatch of Unsafe (and yes generics would be nice). If you have one actor which manipulates a mutable static and once updated it is actually immutable you can hack that with Unsafe. But the best design is to make your static fields an AtomicRef and ensure one actor is responsible for updating it with an immutable instance.

Right now, I think @qualidafial's suggest of ActorLocal makes a ton of sense. Another case along with Unsafe and Atomics where a simple generics system would really be nice (not that I am planning on doing that anytime soon :-)

rfeldman Mon 17 Jan 2011

-1 to ActorLocal - it's better than just Actor.locals, but mandating that type safety be thrown out the window in the course of using concurrency normally is blech.

qualidafial Fri 28 Jan 2011

@rfeldman: I see your point, but there's already no type safety to throw out--'Actor.locals' is just a Str:Obj?, you can stuff anything in there.

One possible runtime solution would be to imply the type of the reference from the initializer function:

const class Foo
{
  ActorLocal bar := ActorLocal |->Bar| { Bar() }
}

In this case, the ActorLocal instance would determine the reference type from the passed in Func's return type, and could enforce that type before storing new values.

rfeldman Fri 28 Jan 2011

Agreed that it wouldn't be any less type-unsafe than the present solution; my point is that if it's going to be retooled I'd rather it be retooled into something that allows real type safety.

The above would be closer, but I have to think there's some way for normal type safety and normal concurrency usage to coexist.

Login or Signup to reply.