www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - A delegate problem, create delegation in loop

reply lijie <cpunion gmail.com> writes:
--bcaec54ee3ee7f7e4104c40ec69a
Content-Type: text/plain; charset=UTF-8

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 --bcaec54ee3ee7f7e4104c40ec69a Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable <div>Hi,</div><div><br></div><div>My test code:</div><div>=C2=A0</div><bloc= kquote class=3D"gmail_quote" style=3D"margin-top:0px;margin-right:0px;margi= n-bottom:0px;margin-left:0.8ex;border-left-width:1px;border-left-color:rgb(= 204,204,204);border-left-style:solid;padding-left:1ex"> import std.stdio;<br>void main() {<br>=C2=A0 =C2=A0 void delegate()[] funct= ions;<br>=C2=A0 =C2=A0 foreach (i; 0 .. 5) {<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0= functions ~=3D {<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 printf(&quot= ;%d\n&quot;, i);<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 };</blockquote><blockquote = class=3D"gmail_quote" style=3D"margin-top:0px;margin-right:0px;margin-botto= m:0px;margin-left:0.8ex;border-left-width:1px;border-left-color:rgb(204,204= ,204);border-left-style:solid;padding-left:1ex"> =C2=A0 =C2=A0 }<br>=C2=A0 =C2=A0 foreach (func; functions) {<br>=C2=A0 =C2= =A0 =C2=A0 =C2=A0 func();<br>=C2=A0 =C2=A0 }<br>}</blockquote><div><br></di= v><div>output:</div><div><br></div><div><blockquote class=3D"gmail_quote" s= tyle=3D"margin-top:0px;margin-right:0px;margin-bottom:0px;margin-left:0.8ex= ;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style= :solid;padding-left:1ex"> $ dmd</blockquote><blockquote class=3D"gmail_quote" style=3D"margin-top:0px= ;margin-right:0px;margin-bottom:0px;margin-left:0.8ex;border-left-width:1px= ;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1e= x"> DMD64 D Compiler v2.059</blockquote><blockquote class=3D"gmail_quote" style= =3D"margin-top:0px;margin-right:0px;margin-bottom:0px;margin-left:0.8ex;bor= der-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:sol= id;padding-left:1ex"> ...=C2=A0</blockquote><blockquote class=3D"gmail_quote" style=3D"margin-top= :0px;margin-right:0px;margin-bottom:0px;margin-left:0.8ex;border-left-width= :1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-lef= t:1ex"> $ ./main<br>5<br>5<br>5<br>5<br>5</blockquote></div><div><br></div><div>See= ms like all delegations shared a stack variable, I think delegation must co= py the value into its context.</div><div><br></div><div>I can avoid it:</di= v> <div><br></div><div><blockquote class=3D"gmail_quote" style=3D"margin-top:0= px;margin-right:0px;margin-bottom:0px;margin-left:0.8ex;border-left-width:1= px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:= 1ex"> =C2=A0 =C2=A0 void delegate() createDelegate(int i) {<br>=C2=A0 =C2=A0 =C2= =A0 =C2=A0 void exec() {<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 print= f(&quot;%d\n&quot;, i);<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 }<br>=C2=A0 =C2=A0 = =C2=A0 =C2=A0 return &amp;exec;<br>=C2=A0 =C2=A0 }<br>=C2=A0 =C2=A0 foreach= (i; 0 .. 5) {<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 functions ~=3D createDelegate= (i);<br> =C2=A0 =C2=A0 }</blockquote></div><div><br></div><div>But hope for improve = it.</div><div><br></div><div><br></div><div>Best regards,</div><div><br></d= iv><div>-- Li Jie</div> --bcaec54ee3ee7f7e4104c40ec69a--
Jul 04 2012
next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
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
Jul 05 2012
prev sibling next sibling parent reply Denis Shelomovskij <verylonglogin.reg gmail.com> writes:
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
Jul 05 2012
parent Timon Gehr <timon.gehr gmx.ch> writes:
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.
Jul 06 2012
prev sibling next sibling parent lijie <cpunion gmail.com> writes:
--20cf3079bdb0002c9204c42062ef
Content-Type: text/plain; charset=UTF-8

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(); }

Best regards, -- Li Jie --20cf3079bdb0002c9204c42062ef Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable On Thu, Jul 5, 2012 at 3:36 PM, bearophile <span dir=3D"ltr">&lt;<a href=3D= "mailto:bearophileHUGS lycos.com" target=3D"_blank">bearophileHUGS lycos.co= m</a>&gt;</span> wrote:<br><div class=3D"gmail_quote"><blockquote class=3D"= gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-= left:1ex"> lijie:<div class=3D"im"><br> <br> <blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p= x #ccc solid;padding-left:1ex"><blockquote class=3D"gmail_quote" style=3D"m= argin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"> import std.stdio;<br> void main() {<br> =C2=A0 =C2=A0 void delegate()[] functions;<br> =C2=A0 =C2=A0 foreach (i; 0 .. 5) {<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 functions ~=3D {<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 printf(&quot;%d\n&quot;, i);<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 };<br> </blockquote> <br> =C2=A0 =C2=A0 }<br> <blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p= x #ccc solid;padding-left:1ex"> =C2=A0 =C2=A0 foreach (func; functions) {<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 func();<br> =C2=A0 =C2=A0 }<br> }<br> </blockquote></blockquote> <br> <br> import std.stdio;<br> <br> void main() {<br> =C2=A0 =C2=A0 void delegate()[] functions;<br> <br> =C2=A0 =C2=A0 foreach (i; 0 .. 5)<br></div> =C2=A0 =C2=A0 =C2=A0 =C2=A0 functions ~=3D ((int j) =3D&gt; { printf(&quot;= %d\n&quot;, j); })(i);<br> <br> =C2=A0 =C2=A0 foreach (func; functions)<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 func();<br> }<br> <br></blockquote><div><br></div><div>Thanks=C2=A0bearophile.</div><div><br>= </div><div>Best regards,</div><div><br></div><div>-- Li Jie</div></div><br> --20cf3079bdb0002c9204c42062ef--
Jul 05 2012
prev sibling next sibling parent lijie <cpunion gmail.com> writes:
--20cf3068480361e27f04c420a8f1
Content-Type: text/plain; charset=UTF-8

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 --20cf3068480361e27f04c420a8f1 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable <div class=3D"gmail_quote">On Thu, Jul 5, 2012 at 4:26 PM, Denis Shelomovsk= ij <span dir=3D"ltr">&lt;<a href=3D"mailto:verylonglogin.reg gmail.com" tar= get=3D"_blank">verylonglogin.reg gmail.com</a>&gt;</span> wrote:<div>=C2=A0= </div><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-l= eft:1px #ccc solid;padding-left:1ex"> Different situation is for such C# loop:<br> ---<br> for (int i =3D 0; i &lt; funcs.Length; ++i)<br> {<br> =C2=A0 =C2=A0 int t =3D i;<br> =C2=A0 =C2=A0 funcs[i] =3D new MyFunc(() =3D&gt; System.Console.WriteLine(t= ));<br> }<br> ---<br> where &quot;t&quot; is local for scope. Here C# behaves correctly, but D do= esn&#39;t. This D loop<br> ---<br> foreach(i; 0 .. 5) {<br> =C2=A0 =C2=A0 int t =3D i;<br> =C2=A0 =C2=A0 functions ~=3D { printf(&quot;%d\n&quot;, t); };<br> }<br> ---<br> prints &quot;4&quot; five times. It&#39;s Issue 2043:<br> <a href=3D"http://d.puremagic.com/issues/show_bug.cgi?id=3D2043" target=3D"= _blank">http://d.puremagic.com/issues/<u></u>show_bug.cgi?id=3D2043<br></a>= <br></blockquote><div>=C2=A0</div></div><span style=3D"font-family:Arial;fo= nt-size:12px;white-space:pre-wrap">How to distinguish which variables will = be copied to the closure context?</span><div> <span style=3D"font-family:Arial;font-size:12px;white-space:pre-wrap"><br><= /span></div><div><div class=3D"force_dir" style=3D"font-family:Arial;font-s= ize:12px;white-space:pre-wrap"><font lang=3D"en">I think this is a scope ru= le, in the previous code, there are three variables:</font></div> <div class=3D"force_dir" style=3D"font-family:Arial;font-size:12px;white-sp= ace:pre-wrap"><font lang=3D"en">1. function arguments</font></div><div clas= s=3D"force_dir" style=3D"font-family:Arial;font-size:12px;white-space:pre-w= rap"><font lang=3D"en">2. loop variables</font></div> <div class=3D"force_dir" style=3D"font-family:Arial;font-size:12px;white-sp= ace:pre-wrap"><font lang=3D"en">3. local variables</font></div><div class= =3D"force_dir" style=3D"font-family:Arial;font-size:12px;white-space:pre-wr= ap"><font lang=3D"en">Seems only function parameters is copied. In C#, loca= l variables is copied. </font>There are other rules? And why is the loop va= riable not local?</div> </div><div class=3D"force_dir" style=3D"font-family:Arial;font-size:12px;wh= ite-space:pre-wrap"><br></div><div class=3D"force_dir" style=3D"font-family= :Arial;font-size:12px;white-space:pre-wrap">Thanks.</div><div class=3D"forc= e_dir" style=3D"font-family:Arial;font-size:12px;white-space:pre-wrap"> <br></div><div class=3D"force_dir" style=3D"font-family:Arial;font-size:12p= x;white-space:pre-wrap">Best regards,</div><div class=3D"force_dir" style= =3D"font-family:Arial;font-size:12px;white-space:pre-wrap"><br></div><div c= lass=3D"force_dir" style=3D"font-family:Arial;font-size:12px;white-space:pr= e-wrap"> -- Li Jie</div> --20cf3068480361e27f04c420a8f1--
Jul 05 2012
prev sibling parent lijie <cpunion gmail.com> writes:
--20cf30684803a5039a04c42a738d
Content-Type: text/plain; charset=UTF-8

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.

--20cf30684803a5039a04c42a738d Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable On Fri, Jul 6, 2012 at 3:06 PM, Timon Gehr <span dir=3D"ltr">&lt;<a href=3D= "mailto:timon.gehr gmx.ch" target=3D"_blank">timon.gehr gmx.ch</a>&gt;</spa= n> wrote:<br><div class=3D"gmail_quote"><blockquote class=3D"gmail_quote" s= tyle=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"> <div class=3D"im"> <br></div> It is simple. Variable declarations introduce a new variable. Closures<br> that reference the same variable will see the same values.<br> <br> ----<br> <br> foreach(i; 0..3) { functions~=3D{writeln(i);}; }<br> <br> is the same as<br> <br> for(int i=3D0;i&lt;3;i++) { functions~=3D{writeln(i);}; }<br> <br> is the same as<br> <br> {int i=3D0;for(;i&lt;3;i++) { functions~=3D{writeln(i);}; }}<br> <br> is the same as<br> <br> {<br> =C2=A0 =C2=A0 int i=3D0;<br> =C2=A0 =C2=A0 { functions~=3D{writeln(i);}; }<br> =C2=A0 =C2=A0 i++;<br> =C2=A0 =C2=A0 { functions~=3D{writeln(i);}; }<br> =C2=A0 =C2=A0 i++;<br> =C2=A0 =C2=A0 { functions~=3D{writeln(i);}; }<br> =C2=A0 =C2=A0 i++;<br> }<br> <br> <br> ----<br> <br> foreach(i; 0..3){ int j=3Di; functions~=3D{writeln(j);}; }<br> <br> is the same as<br> <br> for(int i=3D0;i&lt;3;i++){ int j=3Di; functions~=3D{writeln(j);}; }<br> <br> is the same as<br> <br> {int i=3D0;for(i&lt;3;i++){ int j=3Di; functions~=3D{writeln(j);}; }<br> <br> is the same as<br> <br> {<br> =C2=A0 =C2=A0 int i=3D0;<br> =C2=A0 =C2=A0 { int j=3Di; functions~=3D{writeln(j);}; }<br> =C2=A0 =C2=A0 i++;<br> =C2=A0 =C2=A0 { int j=3Di; functions~=3D{writeln(j);}; }<br> =C2=A0 =C2=A0 i++;<br> =C2=A0 =C2=A0 { int j=3Di; functions~=3D{writeln(j);}; }<br> =C2=A0 =C2=A0 i++;<br> }<br> <br> ----<br> <br> I think it is quite intuitive.<br> <br> </blockquote></div><br><div>Understood, thanks.</div> --20cf30684803a5039a04c42a738d--
Jul 06 2012