On Sat, Oct 6, 2018 at 7:01 PM Manu <turkey...@gmail.com> wrote: > > On Sat, Oct 6, 2018 at 6:59 PM Manu <turkey...@gmail.com> wrote: > > > > So I'm working on a SMT infrastructure, and expression of > > thread-safety is a core design mechanic... but I'm really struggling > > to express it in terms of the type system. > > I figure I'll throw some design challenges out here and see if anyone > > can offer some good ideas. > > > > The thing I'm trying to model is an attribute along the lines of > > `shared`, but actually useful ;) > > I'll use the attribute `threadsafe` in place of `shared`, and see > > where that goes. > > > > Consider: > > struct Bob > > { > > int x; > > threadsafe Atomic!int y; > > > > void m1(); > > void m2() threadsafe;; > > > > void overloaded(); > > void overloaded() threadsafe; > > } > > > > void func(Bob x, threadsafe Bob y) > > { > > x.x = 10; // fine > > x.y = 10; // fine > > x.m1(); // fine > > x.m2(); // fine > > x.overloaded(); // fine, use the un-threadsafe overload > > > > y.x = 10; // ERROR, a threadsafe reference can NOT modify an > > un-threadsafe member > > y.y = 10; // fine > > x.m1(); // ERROR, method not threadsafe > > x.m2(); // fine > > x.overloaded(); // fine, use the threadsafe overload > > > > threadsafe Bob* p = &x; // can take threadsafe reference to > > thread-local object > > } > > > > This is loosely what `shared` models, but there's a few differences: > > 1. thread-local can NOT promote to shared > > 2. shared `this` applies to members > > > > For `shared` to be useful, it should be that a shared reference to > > something inhibits access to it's thread-local stuff. And in that > > world, then I believe that thread-local promotion to shared would work > > like const does. > > > > I guess I'm wondering; should `shared` be transitive? Perhaps that's > > what's wrong with it...? > > *** the function arguments should be `ref`!
Thinking on this more... perhaps it's the case that shared is transitive, but the effect shared has, is to inhibit read/write to data members. In my example above, there is an atomic data member: struct Bob { int x; Atomic!int y; // not marked `shared` in this example } void fun(ref Bob a, ref shared Bob b) { a.x = 10; // fine a.y = 10; // fine b.x = 10; // error! b is shared, and member 'x' is NOT shared, no access! b.y = 10; // this gets interesting... } So, `b` can't access `y` because it's not shared... but consider this possibility: struct Atomic(T) { T data; void opAssign(T val) shared { // implement assignment using atomic operations } } `b.y.data` is not accessible, but the assignment operator has been attributed shared, which means `b.y = 10` becomes a legal function call. At this point, shared is now useful. So, continue the thought experiment that goes: 1. `shared` instances can NOT access non-shared members (opposite of current behaviour) 2. non-shared can promote to `shared` (like const) I think this restriction in access corrects the issues associated with allowing non-shared -> shared promotion.