How can I put the current value of a variable into a delegate?
    Steven Schveighoffer 
    schveiguy at gmail.com
       
    Mon May  6 16:41:38 UTC 2024
    
    
  
On Monday, 6 May 2024 at 06:29:49 UTC, Liam McGillivray wrote:
> Delegates can be a pain, as they often have results different 
> from what one would intuitively expect. This can easily result 
> in bugs.
>
> Here's a line that caused a bug that took me awhile to find:
> ```
> foreach(card; unitCards) card.submitted = delegate() => 
> selectUnit(card.unit);
> ```
>
> Each `UnitInfoCard` object (which `card` is a member of) 
> contains a `Unit` object called `unit`. The intention of this 
> line was that each object in `unitCards` would call 
> `selectUnit` with it's own `unit` every time it calls 
> `submitted`. Instead, every card calls `submitted` with the 
> *last* value of `card`.
Yes, this is because the foreach loop reuses the same memory slot 
for `card`.
Even though this is allocated as a closure, it still only 
allocates the frame stack of the *enclosing function*, and does 
not allocate a new slot for each loop iteration.
You can force this by using a lambda which allocates the closure:
```d
foreach(card; unitCards)
     card.submitted = (c2) { return () => selectUnit(c2.unit); 
}(card);
```
This is a lambda which accepts `card` as a parameter, and returns 
an appropriate delegate. It is important to use a parameter, 
because if you just use card inside there, it's still using the 
single stack frame of the calling function!
I renamed the inner parameter `c2` to avoid confusion, but you 
could name it `card` also. Essentially, the stack frame of the 
inner function is now allocated a closure, and it has it's own 
reference to `card` as a parameter.
This is a very old issue: 
https://issues.dlang.org/show_bug.cgi?id=2043 since "moved" to 
https://issues.dlang.org/show_bug.cgi?id=23136
I would love to see a solution, but the workaround at least 
exists!
-Steve
    
    
More information about the Digitalmars-d-learn
mailing list