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