Thread overview
A delegate problem, create delegation in loop
Jul 05, 2012
lijie
Jul 05, 2012
bearophile
Jul 06, 2012
lijie
Jul 05, 2012
Denis Shelomovskij
Jul 06, 2012
lijie
Jul 06, 2012
Timon Gehr
Jul 06, 2012
lijie
July 05, 2012
Hi,

My test code:


> import std.stdio;
> void main() {
>     void delegate()[] functions;
>     foreach (i; 0 .. 5) {
>         functions ~= {
>             printf("%d\n", i);
>         };

    }
>     foreach (func; functions) {
>         func();
>     }
> }


output:

$ dmd

DMD64 D Compiler v2.059

...

$ ./main
> 5
> 5
> 5
> 5
> 5


Seems like all delegations shared a stack variable, I think delegation must copy the value into its context.

I can avoid it:

    void delegate() createDelegate(int i) {
>         void exec() {
>             printf("%d\n", i);
>         }
>         return &exec;
>     }
>     foreach (i; 0 .. 5) {
>         functions ~= createDelegate(i);
>     }


But hope for improve it.


Best regards,

-- Li Jie


July 05, 2012
lijie:

>> import std.stdio;
>> void main() {
>>     void delegate()[] functions;
>>     foreach (i; 0 .. 5) {
>>         functions ~= {
>>             printf("%d\n", i);
>>         };
>
>     }
>>     foreach (func; functions) {
>>         func();
>>     }
>> }


import std.stdio;

void main() {
    void delegate()[] functions;

    foreach (i; 0 .. 5)
        functions ~= ((int j) => { printf("%d\n", j); })(i);

    foreach (func; functions)
        func();
}

Bye,
bearophile
July 05, 2012
05.07.2012 9:54, lijie пишет:
> Hi,
>
> My test code:
>
>     import std.stdio;
>     void main() {
>          void delegate()[] functions;
>          foreach (i; 0 .. 5) {
>              functions ~= {
>                  printf("%d\n", i);
>              };
>
>          }
>          foreach (func; functions) {
>              func();
>          }
>     }
>
>
> output:
>     5
>     5
>     5
>     5
>     5

This program behaves as expected. Just like C# program that will give the same output:
---
delegate void MyFunc();

class Program
{
    static void Main()
    {
        var funcs = new MyFunc[5];

        for (int i = 0; i < funcs.Length; ++i)
            funcs[i] = new MyFunc(() => System.Console.WriteLine(i));

        foreach (var f in funcs)
            f();
    }
}
---

because "i" is the same for every iteration. Different situation is for such C# loop:
---
for (int i = 0; i < funcs.Length; ++i)
{
    int t = i;
    funcs[i] = new MyFunc(() => System.Console.WriteLine(t));
}
---
where "t" is local for scope. Here C# behaves correctly, but D doesn't. This D loop
---
foreach(i; 0 .. 5) {
    int t = i;
    functions ~= { printf("%d\n", t); };
}
---
prints "4" five times. It's Issue 2043:
http://d.puremagic.com/issues/show_bug.cgi?id=2043

I'm not posting workaround here because bearophile already did it.

-- 
Денис В. Шеломовский
Denis V. Shelomovskij


July 06, 2012
On Thu, Jul 5, 2012 at 3:36 PM, bearophile <bearophileHUGS@lycos.com> wrote:

> lijie:
>
>
>  import std.stdio;
>>> void main() {
>>>     void delegate()[] functions;
>>>     foreach (i; 0 .. 5) {
>>>         functions ~= {
>>>             printf("%d\n", i);
>>>         };
>>>
>>
>>     }
>>
>>>     foreach (func; functions) {
>>>         func();
>>>     }
>>> }
>>>
>>
>
> import std.stdio;
>
> void main() {
>     void delegate()[] functions;
>
>     foreach (i; 0 .. 5)
>         functions ~= ((int j) => { printf("%d\n", j); })(i);
>
>     foreach (func; functions)
>         func();
> }
>
>
Thanks bearophile.

Best regards,

-- Li Jie


July 06, 2012
On Thu, Jul 5, 2012 at 4:26 PM, Denis Shelomovskij < verylonglogin.reg@gmail.com> wrote:


> Different situation is for such C# loop:
> ---
> for (int i = 0; i < funcs.Length; ++i)
> {
>     int t = i;
>     funcs[i] = new MyFunc(() => System.Console.WriteLine(t));
> }
> ---
> where "t" is local for scope. Here C# behaves correctly, but D doesn't. This D loop
> ---
> foreach(i; 0 .. 5) {
>     int t = i;
>     functions ~= { printf("%d\n", t); };
> }
> ---
> prints "4" five times. It's Issue 2043: http://d.puremagic.com/issues/**show_bug.cgi?id=2043 <http://d.puremagic.com/issues/show_bug.cgi?id=2043>
>

How to distinguish which variables will be copied to the closure context?

I think this is a scope rule, in the previous code, there are three
variables:
1. function arguments
2. loop variables
3. local variables
Seems only function parameters is copied. In C#, local variables is
copied. There
are other rules? And why is the loop variable not local?

Thanks.

Best regards,

-- Li Jie


July 06, 2012
On 07/06/2012 05:14 AM, lijie wrote:
> On Thu, Jul 5, 2012 at 4:26 PM, Denis Shelomovskij
> <verylonglogin.reg@gmail.com <mailto:verylonglogin.reg@gmail.com>> wrote:
>
>     Different situation is for such C# loop:
>     ---
>     for (int i = 0; i < funcs.Length; ++i)
>     {
>          int t = i;
>          funcs[i] = new MyFunc(() => System.Console.WriteLine(t));
>     }
>     ---
>     where "t" is local for scope. Here C# behaves correctly, but D
>     doesn't. This D loop
>     ---
>     foreach(i; 0 .. 5) {
>          int t = i;
>          functions ~= { printf("%d\n", t); };
>     }
>     ---
>     prints "4" five times. It's Issue 2043:
>     http://d.puremagic.com/issues/__show_bug.cgi?id=2043
>     <http://d.puremagic.com/issues/show_bug.cgi?id=2043>
>
> How to distinguish which variables will be copied to the closure context?
>

They are not copied, they are stored there.

> I think this is a scope rule, in the previous code, there are three
> variables:
> 1. function arguments
> 2. loop variables
> 3. local variables
> Seems only function parameters is copied. In C#, local variables is
> copied. There are other rules? And why is the loop variable not local?
>
> Thanks.
>
> Best regards,
>
> -- Li Jie

It is simple. Variable declarations introduce a new variable. Closures
that reference the same variable will see the same values.

----

foreach(i; 0..3) { functions~={writeln(i);}; }

is the same as

for(int i=0;i<3;i++) { functions~={writeln(i);}; }

is the same as

{int i=0;for(;i<3;i++) { functions~={writeln(i);}; }}

is the same as

{
    int i=0;
    { functions~={writeln(i);}; }
    i++;
    { functions~={writeln(i);}; }
    i++;
    { functions~={writeln(i);}; }
    i++;
}


----

foreach(i; 0..3){ int j=i; functions~={writeln(j);}; }

is the same as

for(int i=0;i<3;i++){ int j=i; functions~={writeln(j);}; }

is the same as

{int i=0;for(i<3;i++){ int j=i; functions~={writeln(j);}; }

is the same as

{
    int i=0;
    { int j=i; functions~={writeln(j);}; }
    i++;
    { int j=i; functions~={writeln(j);}; }
    i++;
    { int j=i; functions~={writeln(j);}; }
    i++;
}

----

I think it is quite intuitive.

July 06, 2012
On Fri, Jul 6, 2012 at 3:06 PM, Timon Gehr <timon.gehr@gmx.ch> wrote:

>
> It is simple. Variable declarations introduce a new variable. Closures that reference the same variable will see the same values.
>
> ----
>
> foreach(i; 0..3) { functions~={writeln(i);}; }
>
> is the same as
>
> for(int i=0;i<3;i++) { functions~={writeln(i);}; }
>
> is the same as
>
> {int i=0;for(;i<3;i++) { functions~={writeln(i);}; }}
>
> is the same as
>
> {
>     int i=0;
>     { functions~={writeln(i);}; }
>     i++;
>     { functions~={writeln(i);}; }
>     i++;
>     { functions~={writeln(i);}; }
>     i++;
> }
>
>
> ----
>
> foreach(i; 0..3){ int j=i; functions~={writeln(j);}; }
>
> is the same as
>
> for(int i=0;i<3;i++){ int j=i; functions~={writeln(j);}; }
>
> is the same as
>
> {int i=0;for(i<3;i++){ int j=i; functions~={writeln(j);}; }
>
> is the same as
>
> {
>     int i=0;
>     { int j=i; functions~={writeln(j);}; }
>     i++;
>     { int j=i; functions~={writeln(j);}; }
>     i++;
>     { int j=i; functions~={writeln(j);}; }
>     i++;
> }
>
> ----
>
> I think it is quite intuitive.
>
>
Understood, thanks.