On Wednesday, 28 May 2014 at 14:06:38 UTC, Meta wrote:
What I meant to say by "allocate a closure" is that variables in the stack frame that the delegate has a pointer to are moved to the heap when they go out of scope. I believe this implies GC allocation, but I'm not 100% sure. If that *were* the case, then you can see that marking the delegate as @nogc would mean that code such as your example would fail to compile.

They probably work that way in C++ and Java, but that's not how closures work in D. Take a look at the this example: http://dpaste.dzfl.pl/69c7298b5a12

If you try to run it `foo()` will print different values each time, but `bar()` will always print 0. The reason is that `bar` returns a delegate.

`foo` uses the standard call stack to conform to the C/++ ABI, but `bar` uses a different type of call stack - one that's implemented with a linked list. That way, when `bar` finishes, it's stack frame's memory will not get overwritten by the next function call, and the delegate can safely hold a pointer to it and use it directly.

Now, that doesn't mean there is no GCed memory allocations involved. The stack frame is allocated and GCed, and the delegate object itself is allocated and GCed. But at any rate - these things happen *before* the delegate is called, so the delegate itself is @nogc.

Also, take a look at `baz`. It prints a value for EBP, so it uses the C/C++ ABI, but it clearly uses a delegate with a "closure". I'm not sure if it can be called a closure, since it doesn't hold a pointer to the stack(it doesn't have to), but at any rate - its clear that it can't be body-hashed.


The lambdas in my example don't allocate any memory when you *run* them.

I'm not completely sure whether they will or they won't... But I'm pretty sure that this modified example will:

auto foo()
{
    int a;

    return () => is(typeof(a) : char);
}

void main()
{
    writeln(foo()());
}

The example as a whole allocates memory, but the delegate itself doesn't. A memory is allocated for the delegate when it's created, but when you run the delegate no memory needs to be allocated so the delegate is @nogc.


At any rate, a delegate without a closure is either a `function`(which can be body-hashed without any problem) or a method(which doesn't need body-hashing), so having the @nogc restriction would be pointless even if @nogc prevented closures.

How is this restriction pointless if it means that delegates that couldn't be hashed before due to their context can now be hashed?

OK, I retract that statement. I did farther checking and it turns out that functions can also refer to the context as long as that reference is static. That means that the no-closure restriction can be useful, but it also means that the restriction must also be applied to function lambdas.

Reply via email to