Voldemort declarations inside structs with ctor initialization

Idan Arye via Digitalmars-d digitalmars-d at puremagic.com
Wed May 28 08:58:38 PDT 2014


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.


More information about the Digitalmars-d mailing list