On Thu, Oct 18, 2018 at 5:30 PM Timon Gehr via Digitalmars-d <digitalmars-d@puremagic.com> wrote: > > On 18.10.18 23:34, Erik van Velzen wrote: > > If you have an object which can be used in both a thread-safe and a > > thread-unsafe way that's a bug or code smell. > > Then why do you not just make all members shared? Because with Manu's > proposal, as soon as you have a shared method, all members effectively > become shared.
No they don't, only facets that overlap with the shared method. I tried to present an example before: struct Threadsafe { int x; Atomic!int y; void foo() shared { ++y; } // <- shared interaction only affects 'y' void bar() { ++x; ++y; } // <- not threadsafe, but does not violate foo's commitment; only interaction with 'y' has any commitment associated with it void unrelated() { ++x; } // <- no responsibilities are transposed here, you can continue to do whatever you like throughout the class where 'y' is not concerned } In practise, and in my direct experience, classes tend to have exactly one 'y', and either zero (pure utility), or many such 'x' members. Threadsafe API interacts with 'y', and the rest is just normal thread-local methods which interact with all members thread-locally, and may also interact with 'y' while not violating any threadsafety commitments. > It just seems pointless to type them as unshared anyway > and then rely on convention within @safe code to prevent unsafe > accesses. Because, why? It just makes no sense. The pattern, is almost 100% of cses is: owner does all sorts of stuff... threadsafe interactions with things happen in high-frequency worker things. Parallel-for type workloads happen in bursts, the rest of the program works like normal. Parallel for workloads are restricted to the threadsafe API. > With the proposal I posted in the beginning, you would then not only get > implicit conversion of class references to shared, but also back to > unshared. I'm not sure how your proposal (which felt way more complicated to me) improved on my design. Can you clarify how my very simple design is ineffective? > I think the conflation of shared member functions and thread safe member > functions is confusing. What else can it possibly mean to be a shared method? If it's not threadsafe, it's an insta-crash... > shared on a member function just means that the > `this` reference is shared. And by extension, you can only interact with other threadsafe methods. > The only use case for this is overloading on > shared. No, it's for separating threadsafe methods from those that aren't. Just like const methods separate mutating methods from those that don't. > The D approach to multithreading is that /all/ functions should > be thread safe, but it is easier for some of them because they don't > even need to access any shared state. It is therefore helpful if the > type system cleanly separates shared from unshared state. This is patently untrue. I can't implement any interesting shared architecture with the design as is today. I am also completely free to violate any sense of threadsafety with no restrictions of any kind. Write a shared method, access any members, call it from shared instances, watch the fire burn. I don't understand how you can claim that D's design says that all functions are threadsafe, it's so plainly far from the truth...?