Struggling to implement parallel foreach...

Timon Gehr timon.gehr at gmx.ch
Mon Jun 17 01:38:57 UTC 2019


On 17.06.19 03:17, Manu wrote:
> On Sun, Jun 16, 2019 at 6:00 PM Kagamin via Digitalmars-d
> <digitalmars-d at puremagic.com> wrote:
>>
>> On Saturday, 15 June 2019 at 06:13:09 UTC, Manu wrote:
>>> struct S
>>> {
>>>    void method() shared;
>>> }
>>>
>>> void test()
>>> {
>>>    S s;
>>>    void localFun() shared
>>>    {
>>>      s.method(); // <- s must transitively receive const from the
>>> context pointer, otherwise this doesn't work
>>>    }
>>> }
>>>
>>> Current semantics would reject this, because s is not shared,
>>> and
>>> therefore not accessible by localFun.
>>> The unnecessary complexity inhibits the only useful thing that a
>>> shared function can do.
>>
>> Declare `s` as shared and it will work. It would receive
>> qualifier from context, but unshared variables can't be captured
>> by shared closure to begin with because unshared data can't part
>> of shared context, because that would break the guarantee that
>> unshared data shouldn't be shared. Currently compiler implements
>> check which variables can be captured and which can't.
> 
> I don't think the capture should be shared, only the function argument
> has the shared attribute applied, ie:
> Capture cap;
> void localFun(shared(Capture)* ctx);
> localFun(cap); // <- error: can't pass `Context*` to
> `shared(Context)*`... form there, we can begin to do something
> interesting.
> 
> In you consider the const case, this will work perfectly fine, and
> everything will be as expected with absolutely no magic of any kind.
> immutable local functions can not be called under any circumstances;
> this seems like common sense to me.

It's not common sense, it's nonsense. It should be common sense that it 
is nonsense. I don't understand how you can possibly reach that 
conclusion. Closures with an immutable-qualified context can only 
capture immutable variables. What is so surprising about this?

> inout is fine too, just like const.

Absolutely not. You can't implicitly promote stuff to `inout`.

> shared is the interesting one; we shouldn't be able to pass the
> capture to the function because Context* -> shared(Context)*, but we
> can start to talk about ways this can work.
> One way is that the promotion is actally perfectly valid! Because you
> are calling a local function from the local thread; so the shared
> function will have a shared reference to the local context only for
> the life of the function call, and when it returns, the shared
> reference must end with the function. We can do this by declaring the
> local function: `void localFun(scope shared(Context)* ctx);`
> A shared local function is valid so long as that function does NOT
> escape any of those shared references. It might want to attribute
> `return` too.

This idea is not at all contingent on the nonsensical parts of your 
vision, but I don't know if there is a simple way to make this work. It 
will require more care.

>>From there, parallel foreach can be implemented as a @trusted function.
> 

So your evil master plan is:

1. Make qualified local functions useless.
2. Make qualified local functions more useful.
3. Profit.

Just skip phase 1, please.


More information about the Digitalmars-d mailing list