Manu's `shared` vs the @trusted promise

ag0aep6g anonymous at example.com
Sun Oct 21 22:03:00 UTC 2018


It took me a while to understand Manu's idea for `shared`, and I suspect 
that it was/is the same for others. At the same time, Manu seems 
bewildered about the objections. I'm going to try and summarize the 
situation. Maybe it can help advance the discussion.


(1) How Does Manu's `shared` Interact with @trusted?

With Manu's `shared`, there is implicit conversion from non-`shared` to 
`shared`. It would essentially become a language rule. For that rule to 
be sound, any access to `shared` data must be @system. And more 
challengingly, @system/@trusted code must be written carefully with the 
new rule in mind.

(Manu, you might say that the conversion follows from `shared` methods 
being "guaranteed threadsafe", but I think it's easier to reason this 
way. Anyway, potayto potahto.)

The consequence is: In @trusted code, I have to make sure that I have 
exclusive access to any `shared` data that I use. If code that is not 
under my control can obtain a non-`shared` view of the same data, I have 
failed and my @trusted code is invalid.

An example in code (just rehashing code given by Manu):

----
struct Atomic
{
     private int x;

     void incr() shared @trusted
     {
         /* ... atomically increment x ... */
     }

     /* If this next method is here, the one above is invalid. It's the
     responsibility of the author of the @trusted code to make sure
     that this doesn't happen. */

     void badboy() @safe { ++x; } /* NO! BAD! NOT ALLOWED! */
}
----


(2) What's Wrong with That?

The @trusted contract says that an @trusted function must be safe when 
called from an @safe function. That calling @safe function might be 
located in the same module, meaning it might have the same level of 
access as the @trusted function.

That means, Atomic.incr is invalid. It's invalid whether Atomic.badboy 
exists or not. It's invalid because we can even possibly write an 
Atomic.badboy. That's my interpretation of the spec, at least.

But according to Manu, Atomic.incr is fine as long as there's no 
Atomic.badbody that messes things up. So it looks like we're expected to 
violate the @trusted contract when dealing with Manu's `shared`. But 
when we routinely have to break the rules, then that's a sign that the 
rules are bad.


(3) Maybe It Can Be Made to Work?

There might be a way to implement Atomic without breaking the @trusted 
promise:

----
struct Atomic
{
     shared/*!*/ int x;

     void incr() shared @trusted { /* ... */ }

     /* Now this gets rejected by the compiler: */
     void badboy() @safe { ++x; } /* compiler error  */
}
----

With a `shared int x` there's no way that @safe code might access it, so 
the @trusted promise is kept.

Manu, I don't know if marking fields like this is compatible with your 
plans. But it would address the @safe-ty issue, I think.

However, even if it's possible to reconcile Manu's `shared` with @safe 
and @trusted, that doesn't mean it's automatically golden, of course. It 
would be an enormous breaking change that should be well thought-out, 
scrutinized, planned, and executed.


More information about the Digitalmars-d mailing list