On 10/1/18 7:09 PM, Manu wrote:
On Mon, Oct 1, 2018 at 8:55 AM Timon Gehr via Digitalmars-d
<digitalmars-d@puremagic.com> wrote:

On 01.10.2018 04:29, Manu wrote:
struct Bob
{
    void setThing() shared;
}

As I understand, `shared` attribution intends to guarantee that I dun
synchronisation internally.
This method is declared shared, so if I have shared instances, I can
call it... because it must handle thread-safety internally.

void f(ref shared Bob a, ref Bob b)
{
    a.setThing(); // I have a shared object, can call shared method

    b.setThing(); // ERROR
}

This is the bit of the design that doesn't make sense to me...
The method is shared, which suggests that it must handle
thread-safety. My instance `b` is NOT shared, that is, it is
thread-local.
So, I know that there's not a bunch of threads banging on this
object... but the shared method should still work! A method that
handles thread-safety doesn't suddenly not work when it's only
accessed from a single thread.
...

shared on a method does not mean "this function handles thread-safety".
It means "the `this` pointer of this function is not guaranteed to be
thread-local". You can't implicitly create an alias of a reference that
is supposed to be thread-local such that the resulting reference can be
freely shared among threads.

I don't understand. That's the point of `scope`... is that it won't
escape the reference. 'freely shared' is the antithesis of `scope`.

I feel like I don't understand the design...
mutable -> shared should work the same as mutable -> const... because
surely that's safe?

No. The main point of shared (and the main thing you need to understand)
is that it guarantees that if something is _not_ `shared` is is not
shared among threads. Your analogy is not correct, going from
thread-local to shared is like going from mutable to immutable.

We're talking about `mutable` -> `shared scope`. That's like going
from mutable to const.
`shared scope` doesn't say "I can share this", what it says is "this
may be shared, but *I won't share it*", and that's the key.
By passing a thread-local as `shared scope`, the receiver accepts that
the argument _may_ be shared (it's not in this case), but it will not
become shared in the call. That's the point of scope, no?

If the suggested typing rule was implemented, we would have the
following way to break the type system, allowing arbitrary aliasing
between mutable and shared references, completely defeating `shared`:

class C{ /*...*/ }

shared(C) sharedGlobal;
struct Bob{
      C unshared;
      void setThing() shared{
          sharedGlobal=unshared;
      }
}

void main(){
      C c = new C(); // unshared!
      Bob(c).setThing();
      shared(D) d = sharedGlobal; // shared!
      assert(c !is d); // would fail (currently does not even compile)
      // sendToOtherThread(d);
      // c.someMethod(); // (potential) race condition on unshared data
}

Your entire example depends on escaping references. I think you missed
the point?


The problem with mutable wildcards is that you can assign them.

This exposes the problem in your design. The reason const works is because you can't mutate it. Shared is not the same.

simple example:

void foo(scope shared int *a, scope shared int *b)
{
   a = b;
}

If I can bind a to a local mutable int pointer, and b as a pointer to global shared int, the assignment is now considered OK (types and scopes are the same), but now my local points at a shared int without the shared adornments.

The common wildcard you need between shared and mutable is *unique*. That is, even though it's typed as shared or unshared, the compiler has guaranteed there is no other reference to that data. In that case, you can move data from one place to another without compromising the system (as you assign from one unique pointer to another, the original must have to be nullified, otherwise the wildcard still would not work, and the unique property would cease to be accurate).

IMO, the correct way to deal with shared would be to make it 100% unusable. Not readable, or writable. And then you have to cast away shared to make it work (and hopefully performing the correct locking to make sure your changes are defined). I don't think there's a magic bullet that can fix this.

-Steve

Reply via email to