I've talked about this previously, but sometimes I find myself needing to escape the restrictions regarding passing mutable objects between threads. A good example is passing a byte buffer between threads or an accumulation of results. Making these objects either immutable or serializable is too expensive. In these cases I know that once I pass the object to another thread that I am not going reference it anymore.
So the question is how we allow it. The default behavior should continue as it works now - you must pass either an immutable or serialization object between threads.
My proposal for the mutable escape hatch is to create a wrapper type sys::Unsafe with a signature:
class const Unsafe
{
new make(Obj? v) { val = v }
Obj? val
}
This class can be used to box any mutable object, but will return true for isImmutable.
JohnDGFri 30 Jan 2009
An alternative approach used by some models is uniqueness typing. Under this approach, you would explicitly denote a unique type, perhaps using a keyword; e.g. unique.
It's a bit tricky trying to integrate this approach with Fan, but here's one idea: if a parameter is declared with the keyword unique, then the calling code must not ever copy the reference or refer to it after invoking the method.
This problem could also be solved with compiler-generated, aggressive automatic ref counting, with the strict rule that if you pass a var to a method, and don't store any refs to the var or use it after the method invocation, then when the method itself checks the refcount of the var, it will be identically equal to 1. This would be more broadly useful but more difficult to implement and not provide the assurances of compile-time safety.
brianSat 31 Jan 2009
Good ideas there. I think that sort of thing is along the lines of a Linear Type System.
But I believe trying to annotate the type system is too complex compared to a simple wrapper type. That raises all sorts of sticky questions:
how do I reflect that at runtime for checking?
how does it mix with immutable types and serializable types in a common API like Thread?
how does it work for return values?
I guess my feeling is that we should start off simple using a wrapper type, versus trying to add a fairly complex concept into the language. We can still extend the type system in the future once we understand more about concurrency in Fan.
If we did do something more advanced, I would probably want to do something like refs in Clojure.
JohnDGSat 31 Jan 2009
how do I reflect that at runtime for checking?
You only need it for dynamic invocation. Otherwise, all the checking is done at compile time. Of course, you use the type database to tag a parameter as unique when it is declared as such.
how does it mix with immutable types and serializable types in a common API like Thread?
A unique parameter is orthogonal to all of that. Thread would get a new method to send a unique type.
how does it work for return values?
unique would only be allowed on parameters.
If we did do something more advanced, I would probably want to do something like refs in Clojure.
That wouldn't solve your current problem. Clojure's refs are for STM. I don't see an obvious way to use them for message passing.
I guess my feeling is that we should start off simple using a wrapper type
Sure. I just wanted to briefly mention how this problem has been solved elsewhere, in a way that guarantees compile-time safety. Unsafe will work and has the added benefit (if indeed you consider it one) that it can be "abused" to share memory between threads, which opens Fan up to other concurrency models (albeit in an awkward way, but with an STM DSL, that could be hidden).
heliumSat 31 Jan 2009
While I was the one who mentioned uniqueness types in the previous discussion I don't think that it's something I want in Fan.
Why wouldn't unique be allowed on return types? That would be a serve and uneccessary limitation.
I see the big problem with method calls on unique variables. I have to make sure this isn't copyied inside the method. You could do it similar to C++ where you can mark this as const in a method (in this case you would mark it as unique). But I think that would compicate the language too much.
brian Fri 30 Jan 2009
I've talked about this previously, but sometimes I find myself needing to escape the restrictions regarding passing mutable objects between threads. A good example is passing a byte buffer between threads or an accumulation of results. Making these objects either immutable or serializable is too expensive. In these cases I know that once I pass the object to another thread that I am not going reference it anymore.
So the question is how we allow it. The default behavior should continue as it works now - you must pass either an immutable or serialization object between threads.
My proposal for the mutable escape hatch is to create a wrapper type
sys::Unsafe
with a signature:This class can be used to box any mutable object, but will return true for
isImmutable
.JohnDG Fri 30 Jan 2009
An alternative approach used by some models is uniqueness typing. Under this approach, you would explicitly denote a unique type, perhaps using a keyword; e.g.
unique
.It's a bit tricky trying to integrate this approach with Fan, but here's one idea: if a parameter is declared with the keyword
unique
, then the calling code must not ever copy the reference or refer to it after invoking the method.This problem could also be solved with compiler-generated, aggressive automatic ref counting, with the strict rule that if you pass a var to a method, and don't store any refs to the var or use it after the method invocation, then when the method itself checks the refcount of the var, it will be identically equal to 1. This would be more broadly useful but more difficult to implement and not provide the assurances of compile-time safety.
brian Sat 31 Jan 2009
Good ideas there. I think that sort of thing is along the lines of a Linear Type System.
But I believe trying to annotate the type system is too complex compared to a simple wrapper type. That raises all sorts of sticky questions:
I guess my feeling is that we should start off simple using a wrapper type, versus trying to add a fairly complex concept into the language. We can still extend the type system in the future once we understand more about concurrency in Fan.
If we did do something more advanced, I would probably want to do something like refs in Clojure.
JohnDG Sat 31 Jan 2009
You only need it for dynamic invocation. Otherwise, all the checking is done at compile time. Of course, you use the type database to tag a parameter as
unique
when it is declared as such.A unique parameter is orthogonal to all of that. Thread would get a new method to send a unique type.
unique
would only be allowed on parameters.That wouldn't solve your current problem. Clojure's refs are for STM. I don't see an obvious way to use them for message passing.
Sure. I just wanted to briefly mention how this problem has been solved elsewhere, in a way that guarantees compile-time safety.
Unsafe
will work and has the added benefit (if indeed you consider it one) that it can be "abused" to share memory between threads, which opens Fan up to other concurrency models (albeit in an awkward way, but with an STM DSL, that could be hidden).helium Sat 31 Jan 2009
While I was the one who mentioned uniqueness types in the previous discussion I don't think that it's something I want in Fan.
Why wouldn't
unique
be allowed on return types? That would be a serve and uneccessary limitation.I see the big problem with method calls on unique variables. I have to make sure
this
isn't copyied inside the method. You could do it similar to C++ where you can markthis
asconst
in a method (in this case you would mark it asunique
). But I think that would compicate the language too much.