The collect method runs the passed in function and returns an array of all the Watcher instances created during the execution of the function:
watchers := Watcher.collect {
// Binding expressions creates a watcher for each nested property.
// The following binding would create a Watcher for Model.customer,
// Customer.firstName and Text.text properties.
Bind.twoWay(
Bind.from(model, 'customer.firstName'),
Bind.from(firstNameText, 'text'))
}
...
// clean up all listeners e.g. after an editing context has expired
watchers.each { unwatch }
This worked in Flex because the Flash runtime is single-threaded, and static fields can be non-const.
In Java I can use a private static final ThreadLocal to ensure that each thread gets its own watchers accumulator.
In Fantom all statics must be const, so I cannot use this approach. I could use Actor.locals but I don't care for it since locals is visible to any code on the thread/actor. I would like some way to declare an actor-local variable without having to expose my actor's state to the rest of the world.
My current workaround is to use [java]java.lang::ThreadLocal, however I'd like to replace this with pure Fantom code at some point.
brianTue 5 Oct 2010
This was discussed in #1193, just to recap my thoughts:
Now the second issue (which is what you are probably getting at), is that once the function is called in the actor's context, that function could potentially access Actor.locals which would be considered private state. But this is only a problem assuming:
you know the private key used in the locals map
you know the data structure used in the locals map
the data structure used in the locals map is actually public
So I would consider Actor.locals to be encapsulated from a pragmatic perspective. But Fantom doesn't absolutely enforce encapsulation if you really want to break the documented rules. For example you can use the "->" operator to access internal/private slots.
So in some sense Fantom relies on conventions. You can access Actor.local state or private slots, but you do so knowingly that you are breaking the encapsulation of the public API and there is no guarantee that you are using a published, stable interface.
qualidafialTue 5 Oct 2010
From a runtime security perspective there are several problems with this:
1. you know the private key used in the locals map
Actor.locals.keys.each { echo(it) } // TA DA!
2. you know the data structure used in the locals map
In many cases this is a simple matter of inspection.
The runtime type of the value is Watcher[] which tells you a lot already. There is little you could not learn about the locals map through basic runtime inspection.
3. the data structure used in the locals map is actually public
On the main thread, the locals map is as secure as a public whiteboard. Truthfully this is my main concern. The fact that the locals map is keyed by Str means there is a non-zero chance your locals could be overwritten by some other code that uses the same key for a different purpose. This problem would not exist if we had thread/actor locals.
brianTue 5 Oct 2010
I guess it depends on what you mean by "security". I don't consider Fantom's encapsulation model to be "security". It is just a basic convention to clearly delineate what is public and what is private implementation details.
In our commercial product we define public APIs that we support. And we have all sorts of non-public APIs which might be private, internal, public with @NoDoc, or use Actor.locals. I don't personally obsess that there isn't some hard security model around the non-public stuff. But when it comes to support and backward compatibility, using that stuff is at your own risk.
brianWed 6 Oct 2010
Just a couple more thoughts...
I just want to frame the discussion that Fantom encapsulation is not a security model. We should never depend on what Fantom does from a true security point of view like Java might do to isolate applets.
The other thing about Actor.locals is that they are bit hackish to begin with, which is why I don't know if we should consider resurrecting the idea of actorlocal modifier for fields - see #204.
qualidafialFri 8 Oct 2010
I just want to frame the discussion that Fantom encapsulation is not a security model. We should never depend on what Fantom does from a true security point of view like Java might do to isolate applets.
Sorry, I shouldn't have said security, it's an overloaded term and was not taken the way I meant. I was speaking only about access modifiers e.g. public, private, etc.
I need static actor-local state in a class, and I want it to be private. However because of the rule that static fields must be const, the only (pure Fantom) option left to me is put that state in Actor.locals.
I'm developing a library that's intended to be re-used, so I'm not comfortable that my only option exposes my internal state to the entire thread.
The other thing about Actor.locals is that they are bit hackish to begin with, which is why I don't know if we should consider resurrecting the idea of actorlocal modifier for fields - see #204.
I'm a little confused by your wording, are you suggesting you want to eliminate Actor.locals in favor of the actorlocal keyword proposal?
Personally I would favor this, it seems it would solve my present problem.
brianFri 8 Oct 2010
Yeah, I am definitely thinking actorlocal might be a nice feature. Using Actor.locals seems to happen enough that a first language feature might warrant it. I got the idea originally from .NET that has a threadlocal attribute you can annotate a field with.
MoOmSun 10 Oct 2010
I think an actorlocal keyword would be definitely great!
It would also release the rule that says that static fields must be const. We could indeed have a non const static actorlocal field, without breaking the thread-safety, right?
qualidafial Tue 5 Oct 2010
While working on my data binding framework I came across a problem. Here's what I'm trying to achieve:
The
collect
method runs the passed in function and returns an array of all theWatcher
instances created during the execution of the function:This worked in Flex because the Flash runtime is single-threaded, and static fields can be non-const.
In Java I can use a
private static final ThreadLocal
to ensure that each thread gets its ownwatchers
accumulator.In Fantom all statics must be const, so I cannot use this approach. I could use
Actor.locals
but I don't care for it sincelocals
is visible to any code on the thread/actor. I would like some way to declare an actor-local variable without having to expose my actor's state to the rest of the world.My current workaround is to use
[java]java.lang::ThreadLocal
, however I'd like to replace this with pure Fantom code at some point.brian Tue 5 Oct 2010
This was discussed in #1193, just to recap my thoughts:
Now the second issue (which is what you are probably getting at), is that once the function is called in the actor's context, that function could potentially access
Actor.locals
which would be considered private state. But this is only a problem assuming:So I would consider Actor.locals to be encapsulated from a pragmatic perspective. But Fantom doesn't absolutely enforce encapsulation if you really want to break the documented rules. For example you can use the "->" operator to access internal/private slots.
So in some sense Fantom relies on conventions. You can access Actor.local state or private slots, but you do so knowingly that you are breaking the encapsulation of the public API and there is no guarantee that you are using a published, stable interface.
qualidafial Tue 5 Oct 2010
From a runtime security perspective there are several problems with this:
In many cases this is a simple matter of inspection.
Even if you obfuscate the keys:
The runtime type of the value is
Watcher[]
which tells you a lot already. There is little you could not learn about the locals map through basic runtime inspection.On the main thread, the locals map is as secure as a public whiteboard. Truthfully this is my main concern. The fact that the locals map is keyed by
Str
means there is a non-zero chance your locals could be overwritten by some other code that uses the same key for a different purpose. This problem would not exist if we had thread/actor locals.brian Tue 5 Oct 2010
I guess it depends on what you mean by "security". I don't consider Fantom's encapsulation model to be "security". It is just a basic convention to clearly delineate what is public and what is private implementation details.
In our commercial product we define public APIs that we support. And we have all sorts of non-public APIs which might be private, internal, public with @NoDoc, or use Actor.locals. I don't personally obsess that there isn't some hard security model around the non-public stuff. But when it comes to support and backward compatibility, using that stuff is at your own risk.
brian Wed 6 Oct 2010
Just a couple more thoughts...
I just want to frame the discussion that Fantom encapsulation is not a security model. We should never depend on what Fantom does from a true security point of view like Java might do to isolate applets.
The other thing about Actor.locals is that they are bit hackish to begin with, which is why I don't know if we should consider resurrecting the idea of
actorlocal
modifier for fields - see #204.qualidafial Fri 8 Oct 2010
Sorry, I shouldn't have said security, it's an overloaded term and was not taken the way I meant. I was speaking only about access modifiers e.g.
public
,private
, etc.I need static actor-local state in a class, and I want it to be private. However because of the rule that
static
fields must beconst
, the only (pure Fantom) option left to me is put that state inActor.locals
.I'm developing a library that's intended to be re-used, so I'm not comfortable that my only option exposes my internal state to the entire thread.
I'm a little confused by your wording, are you suggesting you want to eliminate
Actor.locals
in favor of theactorlocal
keyword proposal?Personally I would favor this, it seems it would solve my present problem.
brian Fri 8 Oct 2010
Yeah, I am definitely thinking actorlocal might be a nice feature. Using Actor.locals seems to happen enough that a first language feature might warrant it. I got the idea originally from .NET that has a threadlocal attribute you can annotate a field with.
MoOm Sun 10 Oct 2010
I think an
actorlocal
keyword would be definitely great!It would also release the rule that says that static fields must be const. We could indeed have a non const
static actorlocal
field, without breaking the thread-safety, right?