antwarpes
antwarpes

Reputation: 2277

Strange Behavior with Closure in Google's Dartlang

I would have expected the integer 'i' in this Dart program to have been set to 9 before the first function was called. However the output for this program is...

0, 2, 4, 6, 8, 10, 12 ,14, 16, 18

When I would have normally expected 10, 11, 12, 13.... as it is with JavaScript, C# etc..

Dart Lang Output: 0, 2, 4, 6, 8, 10, 12 ,14, 16, 18

typedef int TestFun(int x);

void main()
{
    List<TestFun> functionList = new List<TestFun>();

    for ( int i = 0; i < 10; i++) {        
        functionList.add( (int x) => x + i );      
    }

    for ( int j = 0; j < 10; j++) 
    {
        print(functionList[j](j));
    }    
}

Equivalent JavaScript.... Output 10,11,12...

var functionList = new Array;

for ( var i = 0; i < 10; i++) {
    functionList[i] = function (x) { return x + i } ;
}

for ( var j = 0; j < 10; j++) {
    alert( functionList[j](j) );
}

Equivalent C#.... Output 10,11,12...

public delegate int TestDel(int x);

public static void Main(string[] args)
{
    IList<TestDel> functionList = new List<TestDel>();

    for ( int i = 0; i < 10; i++) 
    {
        functionList.Add((int x) => x + i);      
    }

    for ( int j = 0; j < 10; j++) 
    {
        System.Console.WriteLine(functionList[j](j));
    }    
}

Is this a Dart bug? Can someone explain this behavior to me?

Upvotes: 2

Views: 317

Answers (2)

lrn
lrn

Reputation: 71783

Dart deliberately avoids the error-prone behavior of JavaScript here. A for loop that declares its own variable will have a new version of that variable for each iteration. This goes both for for(var x = ...;;) and for (var x in ...) (and in the latter case, the variable can even be final).

Example showing that each iteration introduces a new independent variable:

class Box {
  final Function set;
  final Function get;
  Box(this.get, this.set);
  String toString() => "[${get()}]";
}
main() {
  var boxes = [];
  for (int i = 0; i < 5; i++) {
    boxes.add(new Box(()=>i, (x) { i = x; }));
  }
  print(boxes);  // [[0], [1], [2], [3], [4]]
  for (int i = 0; i < 5; i++) { 
    boxes[i].set(i * 2 + 1); 
  }
  print(boxes);  // [[1], [3], [5], [7], [9]]
}

Upvotes: 7

G&#252;nter Z&#246;chbauer
G&#252;nter Z&#246;chbauer

Reputation: 657781

Your conclusion seems weird to me.

The first closure you add is actually (i = 0)

functionList[i] = function (x) { return x + 0 } ;

In the second for loop (first iteration) you execute this first function with the argument 0. How should this result to 10?

EDIT

To avoid the behavior mentioned by lrn you can put the variable inside an object

typedef int TestFun(int x);

class Int {
  int val;
  Int(this.val);
}

void main() {
  List<TestFun> functionList = [];

  for (Int i = new Int(0); i.val < 10; i.val++) {
    functionList.add((int x) => x + i.val);
  }

  for (int j = 0; j < 10; j++) {
    print(functionList[j](j));
  }
}

Upvotes: 0

Related Questions