Delegate, scope and associative array
Steven Schveighoffer via Digitalmars-d-learn
digitalmars-d-learn at puremagic.com
Tue Jun 3 06:30:15 PDT 2014
On Mon, 02 Jun 2014 19:43:58 -0400, Rene Zwanenburg
<renezwanenburg at gmail.com> wrote:
> On Monday, 2 June 2014 at 20:09:12 UTC, Edwin van Leeuwen wrote:
>> I'm probably missing something basic, but I am confused by what is
>> going on in the following code.
>>
>> unittest {
>> size_t delegate()[size_t] events;
>> foreach( i; 1..4 ) {
>> events[i] = { return i; };
>> }
>> writeln( events[1]() ); // This outputs 3
>> assert( events[1]() == 1 );
>> }
>>
>> I thought that i should be copied from the local scope and therefore
>> when I call events[1]() the return value should be 1, but in this case
>> it is 3 (it always seems to be the last value of i in the loop).
>>
>> Cheers, Edwin
>
> Yeah this is a known problem. At the moment the foreach loop is
> internally rewritten to something like
>
> int i = 1;
> while(i < 4)
> {
> // foreach loop body
>
> ++i;
> }
>
> While it usually would be preferrable if it were rewritten as
>
> int __compilergeneratedname = 1;
> while(__compilergeneratedname < 4)
> {
> auto i = __compilergeneratedname++;
>
> // foreach loop body
> }
>
> With the current approach every delegate refers to the same variable.
> Another problem is that it's possible to alter the iteration index from
> inside the foreach body.
>
> As you may have guessed, a workaround is to copy the iteration variable
> yourself:
>
> unittest {
> size_t delegate()[size_t] events;
> foreach(_i; 1..4 ) {
> auto i = _i;
> events[i] = { return i; };
> }
> assert( events[1]() == 1 );
> }
>
> This should work though it's less than ideal. There is an open bug
> report:
> https://issues.dlang.org/show_bug.cgi?id=8621
There is a school of thought (to which I subscribe) that says you
shouldn't allocate a separate closure for each loop iteration.
Basically, a closure will only use the stack frame of the calling
function, not any loop iteration.
This way, you can clearly delineate what scope the closure has, and avoid
unnecessary allocations.
-Steve
More information about the Digitalmars-d-learn
mailing list