View mode: basic / threaded / horizontal-split · Log in · Help
July 05, 2012
A delegate problem, create delegation in loop
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
Re: A delegate problem, create delegation in loop
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
Re: A delegate problem, create delegation in loop
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
Re: A delegate problem, create delegation in loop
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
Re: A delegate problem, create delegation in loop
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
Re: A delegate problem, create delegation in loop
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
Re: A delegate problem, create delegation in loop
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.
Top | Discussion index | About this forum | D home