www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Erroneous usage of variable capture in loops

reply FreeSlave <freeslave93 gmail.com> writes:
As known this code will not work as we may expect:

import std.stdio;

void main(string[] args)
{
     void delegate ()[] delegates;
     foreach(i; 0..10) {
         int j = i;
         delegates ~= delegate() {
             writeln(j);
         };
     }
     foreach(dlgt; delegates) {
         dlgt();
     }
}

All delegates will capture the last value of 'j'.

dmd does not complain about such case at all. Once I made this 
mistake myself but noticed it thanks to unittesting. Recently I 
found similar erroneous code in dlangui (no PR yet). Probably 
there are more projects that have the same mistake unnoticed.

May be compiler should produce error or at least generate warning 
on this code.
Jun 02 2017
next sibling parent ketmar <ketmar ketmar.no-ip.org> writes:
FreeSlave wrote:

 As known this code will not work as we may expect:

 import std.stdio;

 void main(string[] args)
 {
      void delegate ()[] delegates;
      foreach(i; 0..10) {
          int j = i;
          delegates ~= delegate() {
              writeln(j);
          };
      }
      foreach(dlgt; delegates) {
          dlgt();
      }
 }

 All delegates will capture the last value of 'j'.

 dmd does not complain about such case at all. Once I made this mistake 
 myself but noticed it thanks to unittesting. Recently I found similar 
 erroneous code in dlangui (no PR yet). Probably there are more projects 
 that have the same mistake unnoticed.

 May be compiler should produce error or at least generate warning on this 
 code.
i'm not even sure that it is detectable. what if i'll insert: if (i == args.length) break; i.e. i *know* about the effect, and still want to do it? i can use it to capture some struct and break, for example. detecting this is kind of halting problem. and there is absolutely no way to hush the compiler, so it will always emit warning.
Jun 02 2017
prev sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 02.06.2017 16:03, FreeSlave wrote:
 As known this code will not work as we may expect:
 
 import std.stdio;
 
 void main(string[] args)
 {
      void delegate ()[] delegates;
      foreach(i; 0..10) {
          int j = i;
          delegates ~= delegate() {
              writeln(j);
          };
      }
      foreach(dlgt; delegates) {
          dlgt();
      }
 }
 
 All delegates will capture the last value of 'j'.
 
 dmd does not complain about such case at all. Once I made this mistake 
 myself but noticed it thanks to unittesting. Recently I found similar 
 erroneous code in dlangui (no PR yet). Probably there are more projects 
 that have the same mistake unnoticed.
 
 May be compiler should produce error or at least generate warning on 
 this code.
It should just generate correct code. This is a compiler bug. https://issues.dlang.org/show_bug.cgi?id=2043
Jun 02 2017