shared - i need it to be useful

Stanislav Blinov stanislav.blinov at gmail.com
Sat Oct 20 19:46:50 UTC 2018


On Saturday, 20 October 2018 at 18:30:59 UTC, Manu wrote:
> On Sat, Oct 20, 2018 at 9:45 AM Stanislav Blinov via 
> Digitalmars-d <digitalmars-d at puremagic.com> wrote:
>>
>> On Saturday, 20 October 2018 at 16:18:53 UTC, aliak wrote:
>>
>> > class C {
>> >   void f();
>> >   void g() shared;
>> > }
>>
>> Those are not "ok". They're only "ok" under Manu's proposal so 
>> long as the author of C promises (via documentation) that 
>> that's indeed "ok". There can be no statically-enforced 
>> guarantees that those calls are "ok", or that issuing them in 
>> that order is "ok". Yet Manu keeps insisting that somehow 
>> there is.
>
> I only insist that if you write a shared method, you promise 
> that it is threadsafe.
> If f() undermines g() threadsafety, then **g() is NOT 
> threadsafe**, and you just write an invalid program.
>
> You can write an invalid program in any imaginable number of 
> ways; that's just not an interesting discussion. An interesting 
> discussion is what we might to to help prevent writing such an 
> invalid program... I don't suggest here what we can do to 
> statically encorce this, but I suspect there does exist *some* 
> options which may help, which can be further developments.
>
> What I also assert is that *this unsafe code is rare*... it 
> exists only at the bottom of the tooling stack, and anyone else 
> using a shared object will not do unsafe, and therefore will 
> not be able to create the problem. If you do unsafety anywhere 
> near `shared`, you should feel nervous. I'm trying to make a 
> world where you aren't *required* to do unsafety at every 
> single interaction.
>
> Understand: f() can only undermine g() promise of threadsafety 
> **if f() is not @safe**. Users won't create this situation 
> accidentally, they can only do it deliberately.

---

module expertcode;

@safe:

struct FileHandle {
     @safe:

     void[] read(void[] storage) shared;
     void[] write(const(void)[] buffer) shared;
}

FileHandle openFile(string path);
// only the owner can close
void closeFile(ref FileHandle);

void shareWithThreads(shared FileHandle*); // i.e. generate a 
number of jobs in some queue
void waitForThreads();                     // waits until all 
processing is done

module usercode;

import expertcode;

void processHugeFile(string path) {
     FileHandle file = openFile(path);
     shareWithThreads(&file);    // implicit cast
     waitForThreads();
     file.closeFile();
}

---

Per your proposal, everything in 'expertcode' can be written 
@safe, i.e. not violating any of the points that @safe forbids, 
or doing so only in a @trusted manner. As far as the language is 
concerned, this would mean that processHugeFile can be @safe as 
well.

Remove the call to `waitForThreads()` (assume user just forgot 
that, i.e. the "accident"). Nothing would change for the 
compiler: all calls remain @safe. And yet, if we're lucky, we get 
a consistent instacrash. If we're unlucky, we get memory 
corruption, or an unsolicited write to another currently open 
file, either of which can go unnoticed for some time.

Of course the program becomes invalid if you do that, there's no 
question about it, this goes for all buggy code. The problem is, 
definition of "valid" lies beyond the type system: it's an 
agreement between different parts of code, i.e. between expert 
programmers who wrote FileHandle et al., and users who write 
processHugeFile(). The main issue is that certain *runtime* 
conditions can still violate @safe-ty.

Your proposal makes the language more strict wrt. to writing 
@safe 'expertmodule', thanks to disallowing reads and writes 
through `shared`, which is great.
However the implicit conversion to `shared` doesn't in any way 
improve the situation as far as user code is concerned, unless 
I'm still missing something.


More information about the Digitalmars-d mailing list