Remove closure allocation
Malte
no at valid.mail
Sun May 27 11:18:43 UTC 2018
On Saturday, 26 May 2018 at 18:10:30 UTC, Neia Neutuladh wrote:
> On Saturday, 26 May 2018 at 15:00:40 UTC, Malte wrote:
>> This compiles with DMD, however it returns random numbers
>> instead of the value I passed in. Looks like a bug to me.
>> Should that work or is there any other pattern I could use for
>> that?
>
> Filed as https://issues.dlang.org/show_bug.cgi?id=18910
>
> As for the larger issue, you have to store `q` somewhere.
>
> The compiler could store it on the stack, but the compiler
> would have to do a lot of work to prove that that's safe --
> that the return value from `arr.map` doesn't escape the current
> function, that `map` doesn't save the thing you passed to it
> anywhere, that sort of thing.
>
> And that sort of analysis is flaky. It's a recipe for code that
> compiles on one version of a compiler and not the next, a lot
> of bug reports that are hard to track down, that sort of thing.
> And it means that it has to assume the worst for functions that
> it doesn't have the source for -- when you pass a delegate,
> when you call an extern(D) function, when you call a virtual
> method.
>
> So the compiler does the safe thing, and it has the GC allocate
> a bit of memory to hold `q`.
>
> The way around that is the `scope` keyword. The compiler can do
> that complex analysis one function at a time; that's
> sufficiently simple. So if you wrote a `map` function, you
> could define it as taking a `scope U delegate(T)` and the
> compiler wouldn't need to use the GC there.
>
> That obviously adds restrictions on how you can write that
> function.
I had filed a bugreport already, but this is only slightly
related. It might be the solution to my problem and just not
working because it's a compiler bug, but could also be supposed
to give me a compile error instead for some reasons I don't know
yet.
I understand the general issue why a closure can be necessary,
but it shouldn't be here, because all I have are value types
(int) and strongly pure function calls. In fact even that
immutable on q should be merely an optimization hint that the
compiler could use the same register when inlining it instead of
having to make a copy.
Adding scope and immutable at will wouldn't be an issue, but it
doesn't solve the problem and wouldn't make sense to me if it did.
In fact, my actual issue is not that I need a @nogc function. I
have a working code that is designed with that principle to have
data transformation using pure functions and I want to
parallelise it by just replacing map with taskPool.amap.
I had exactly that problem before and was more or less randomly
trying to make changes to get rid of the "cannot access frame of
function" error messages. However, if I try to make it a nogc
function first, the compiler gives me useful information like
"onlineapp.identity.__lambda4 closes over variable q at
onlineapp.d(24)", so I can have a closer look at q instead of
blindly guessing why the compiler thinks it needs another frame
pointer.
What I did last time is rewrite the whole function to fit into a
parallel foreach and I guess I have to do the same here too.
It's not that I can't rewrite it to something like
>int identity(immutable int q) pure nothrow @safe @nogc
>{
> static immutable auto arr = [42];
> int getSecondArgument(int a, int b)
> {
> return b;
> }
>
> foreach(i, a; arr) {
> auto tmp = getSecondArgument(a, q);
> if (i==0) return tmp;
> }
>
> assert(0);
>}
, I just don't think I should have to rewrite it that much. But I
currently see no other way to use taskPool and in general I see
very little possibilities to utilize taskPool.amap even though it
looks like a handy tool at first sight, but is just too limited
when you actually try to do something with it.
More information about the Digitalmars-d-learn
mailing list