shared - i need it to be useful

Stanislav Blinov stanislav.blinov at gmail.com
Thu Oct 18 22:10:04 UTC 2018


On Thursday, 18 October 2018 at 21:51:52 UTC, aliak wrote:
> On Thursday, 18 October 2018 at 18:12:03 UTC, Stanislav Blinov 
> wrote:
>> On Thursday, 18 October 2018 at 18:05:51 UTC, aliak wrote:
>>
>>> Right, but the argument is a shared int*, so from what I've 
>>> understood... you can't do anything with it since it has no 
>>> shared members. i.e. you can't read or write to it. No?
>>
>> Obviously the implementation would cast `shared` away, just 
>> like it would if it were Atomic!int. But for some reason, Manu 
>> thinks that latter is OK doing that, but former is voodoo. Go 
>> figure.
>
> Sounds like one is encapsulated within a box that carefully

Unit of "encapsulation" in D is either a module or a package, not 
a struct. Free functions are a very valid way of accessing 
"encapsulated" data.

> handles thread safety and makes promises with the API and the 
> other is not.

Nope.

void foo(const T* x);

makes a promise to not write through x. It assumes '*x' itself 
may not be const.

void foo(shared T* x);

makes a promise to threat '*x' in a thread-safe manner. But per 
MP, it *assumes* that '*x' is shared. And if it isn't, good luck 
finding that spot in your code.

> I don't think you can apply shared on a free function, i.e.:
>
> void increment(shared int*) shared;
>
> in which case increment would not, and cannot be a threadsafe 
> api in Manu's world.

Wrong. In Manu's "world", this is somehow considered "safe":

void T_method_increment(ref shared T);

...because that is what a method is, while this:

void increment(shared T*);
void increment(ref shared T);

...is considered "unsafe" because reasons. Do you see the 
difference in signatures? I sure don't.

> So once you throw an Object in to shared land all you could do 
> is call shared methods on it, and since they'd have been 
> carefully written with sharing in mind... it does seem a lot 
> more usable.

Same goes with free functions.

> On these two cases:
>
> increment(shared int* p1) {
>  // I have no guarantees that protecting and accessing p1 will 
> not cause problems
>  //
>  // but you don't have this guarantee in any world (current nor 
> MP) because you can
>  // never be sure that p1 was not cast from a mutable.
> }

Except that you *have to* *explicitly* cast it, which is:
a) documentation
b) greppable
c) easily fails review for people not authorized to do so

> int* p2;
> increment(p2);
> // I have no guarantee that accessing p2 is safe anymore.
> // But that would apply only if the author of increment was 
> being unsafe.
> // and "increment" cannot be marked as shared.

No. *You*, the caller of an API (the "increment"), do not 
necessarily control that API. By allowing implicit conversion you 
waive all claims on your own data. In Manu's world, "increment" 
*assumes* you're doing the right thing. Yet at the same time, 
Manu happily talks about how only "experts" can do the right 
thing. How these two things co-exist in his world, I have no idea.

The "have no guarantee" holds in both cases. Except case (1) 
would require actually checking what the hell you're doing before 
making a cast, while in case (2) you just blindly write unsafe 
code.


More information about the Digitalmars-d mailing list