On Sun, 13 Sep 2009 15:04:57 -0400, Jeremie Pelletier <jerem...@gmail.com> wrote:
[snip]
Unique data could only be used for aggregate properties, const/immutable data would also be implicitly unique. This qualifier alone would simplify shared quite a lot, allowing the use of unshared objects in shared contexts safely.

Neither const nor immutable data can be considered unique. First, any const data may be being mutated by another routine, so it can't be safely accessed without synchronization. Second, unique data is mutable while const/immutable data is not. Third, most implementations of unique allow for deterministic memory reclamation, which isn't possible if the unique data might actually be const/immutable.

The compiler should make the distinction between shared code and shared data and allow both shared and unshared instances to use shared methods, just like both const and mutable instances may call const methods. An error should also be triggered when calling a shared method of a shared object without synchronization, and maybe have a __sync keyword to override this. If a synchronized method is called from a non-shared object, no synchronization takes place.

I think you have the wrong paradigm in mind. Shared and non-shared aren't mutable and const. They're mutable and immutable. From a technical perspective, synchronization of shared methods are handled by the callee, so there is no way not to call them and non-shared objects don't have a monitor that can be synchronized. Now you can have the compiler use the same code to generate two different object types (vtables, object layouts, etc) with have the same interface, but that doesn't sound like what you're suggesting.

Allow me to illustrate my point with some code:

class Foo {
    int bar() shared { return a; }
    __sync bar2() { synchronized(this) return a; }
    synchronized void foo() { a = 1; }
    int a;
}
auto foo1 = new shared(Foo)();
auto foo2 = new Foo;

foo1.foo(); // ok, synchronized call
synchronized(foo1) foo1.foo(); // warning: recursive synchronization

Why a warning? Monitors are designed to handle recursive synchronization.

foo2.foo(); // ok, unsynchronized call
synchronized(foo2) foo2.foo(); // ok synchronized call

foo1.bar(); // error, unsynchronized call to bar() shared
synchronized(foo1) foo1.bar(); // ok, synchronized call
foo2.bar(); // ok, unsynchronized call
synchronized(foo1) foo1.bar(); // ok, synchronized call

foo1.bar2(); // ok, method handles synchronized
synchronized(foo1) foo1.bar2(); // warning, recursive synchronization
foo2.bar2(); // ok, method handles synchronized, even on unshared object
synchronized(foo2) foo2.bar2(); // warning, recursive synchronization, even on unshared object

That's about it, I believe this behavior would allow quite a number of multi-threaded techniques to be easily implemented and documented. It would only be the most natural thing since its quite similar to how const works.

The major benefit of const isn't method declaration, but object use: i.e. only having to declare func(const T var) and not func(immutable T var) and func(T var). Currently, there's no planned type to fill this role though there have been some proposals.

P.S. Shouldn't 'a' be either private or protected?
P.S.S. Bartosz Milewski has a good series of blogs on multi-threading (with an eye on how to do it well in D).

Bike-shed: I've always preferred the CSP/pi-calculas term 'mobile' for the concept of 'unique'. I think mobile better expresses the concept with regard to multi-threading, where mobile is used to cheaply transfer data between threads (i.e. it moves around/can move between threads, but isn't shared between them). I find 'unique' to mainly convey the memory storage aspect of the concept, which is less important outside of C/C++.

Reply via email to