Jump to page: 1 2
Thread overview
How long does the context of a delegate exist?
May 27, 2021
frame
May 27, 2021
Alain De Vos
May 27, 2021
frame
May 27, 2021
Adam D. Ruppe
May 27, 2021
frame
May 27, 2021
Adam D. Ruppe
May 30, 2021
cc
May 30, 2021
Paul Backus
May 30, 2021
Adam D. Ruppe
May 27, 2021
IGotD-
May 27, 2021

I'm using a buffer delegate to fill data from a DLL and use it as range like this:

Pseudo-Code:

void DLLFun(out Collector collector) {
  auto something;

  collector = Collector(...);
  collector.registerFillBufferMethod({
     auto data = [];
     //...
     // use of something;
     return data;
  )};
}

This collector takes care of the data so the GC cannot collect it while not explicitly closed on the caller side.

But what about the data used in the context of the delegate? Does this data stay as long DllFun is not called again because the DLL stack is paused? Or is this data also volatile and may be collected by the GC anytime?

May 27, 2021

I think of a dynamic array as a value-type consisting of a pointer to the actual data and a length, which gets copied.
The data pointing to will continue to live.
The pointer and length might disappear from the stack or get copied.
I think there is no problem.

May 27, 2021

On Thursday, 27 May 2021 at 12:59:02 UTC, frame wrote:

>

But what about the data used in the context of the delegate?

If the delegate is created by the GC and stored it will still be managed by the GC, along with its captured vars.

As long as the GC can see the delegate in your example you should be OK. But if it is held on to by a C or OS lib, the GC might not see it and you'd have to addRoot or something to ensure it stays in.

May 27, 2021

On Thursday, 27 May 2021 at 16:17:12 UTC, Alain De Vos wrote:

>

I think of a dynamic array as a value-type consisting of a pointer to the actual data and a length, which gets copied.
The data pointing to will continue to live.
The pointer and length might disappear from the stack or get copied.
I think there is no problem.

Seems logical, I just do not know exactly what a delegate internally does with captured variables from the function body. But you are right it must be something like that.

May 27, 2021

On Thursday, 27 May 2021 at 18:13:17 UTC, Adam D. Ruppe wrote:

>

On Thursday, 27 May 2021 at 12:59:02 UTC, frame wrote:

>

But what about the data used in the context of the delegate?

If the delegate is created by the GC and stored it will still be managed by the GC, along with its captured vars.

As long as the GC can see the delegate in your example you should be OK. But if it is held on to by a C or OS lib, the GC might not see it and you'd have to addRoot or something to ensure it stays in.

Did you mean to add the delegate as GC root or the data? It would be nicer to just add the delegate but addRoot does not accept it and casting to void* is deprecated. Does it work if I supply the .ptr property instead? This "GC silently no-op on wrong data" is annoying.

May 27, 2021

On Thursday, 27 May 2021 at 18:13:17 UTC, Adam D. Ruppe wrote:

>

If the delegate is created by the GC and stored it will still be managed by the GC, along with its captured vars.

As long as the GC can see the delegate in your example you should be OK. But if it is held on to by a C or OS lib, the GC might not see it and you'd have to addRoot or something to ensure it stays in.

With lambdas in C++ you can cherrypick captures the way you want, then somehow this can be converted to an std::function and this is where it goes on the heap as well.

In D, how does the compiler know what captures it is supposed to store, or does it take the whole lot?

May 27, 2021

On Thursday, 27 May 2021 at 20:44:21 UTC, frame wrote:

>

Did you mean to add the delegate as GC root or the data?

The delegate.ptr property.

May 27, 2021
On 5/27/21 4:46 PM, IGotD- wrote:
> On Thursday, 27 May 2021 at 18:13:17 UTC, Adam D. Ruppe wrote:
>>
>> If the delegate is created by the GC and stored it will still be managed by the GC, along with its captured vars.
>>
>> As long as the GC can see the delegate in your example you should be OK. But if it is held on to by a C or OS lib, the GC might not see it and you'd have to addRoot or something to ensure it stays in.
> 
> With lambdas in C++ you can cherrypick captures the way you want, then somehow this can be converted to an std::function and this is where it goes on the heap as well.
> 
> In D, how does the compiler know what captures it is supposed to store, or does it take the whole lot?

For closures, it uses semantic analysis to see which variables are used in the lambda, and then allocates a block at the start of the function to hold those variables.

-Steve
May 30, 2021

On Thursday, 27 May 2021 at 20:46:22 UTC, Adam D. Ruppe wrote:

>

On Thursday, 27 May 2021 at 20:44:21 UTC, frame wrote:

>

Did you mean to add the delegate as GC root or the data?

The delegate.ptr property.

Is there any way to enforce at compile time that we're not accidentally allocating when creating a delegate, other than being carefully aware of what variables are referenced inside the body? Something like:

auto dg = delegate {...}
assert(dg.ptr is null, "Oops, we unintentionally allocated on GC here, check delegate body!"); // can't static assert
May 30, 2021

On Sunday, 30 May 2021 at 09:39:28 UTC, cc wrote:

>

Is there any way to enforce at compile time that we're not accidentally allocating when creating a delegate, other than being carefully aware of what variables are referenced inside the body? Something like:

auto dg = delegate {...}
assert(dg.ptr is null, "Oops, we unintentionally allocated on GC here, check delegate body!"); // can't static assert

@nogc. Or check the output of dmd -vgc if you want something less strict.

« First   ‹ Prev
1 2