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.