Search code examples
dartanonymous-functionlexical-closures

Dart. Where argument of anonymous function came from?


In example below there (num i) stuff, where it get it's value when makeAddr() called ?

Function makeAdder(num addBy) {
  return (num i) => addBy + i;
}

void main() {
  // Create a function that adds 2.
  var add2 = makeAdder(2);

  // Create a function that adds 4.
  var add4 = makeAdder(4);

  assert(add2(3) == 5);
  assert(add4(3) == 7);
}

Solution

  • The makeAdder function returns function. The function it returns is created by evaluating the function expression (num i) => addBy + i. When you evaluate a function expression you create a function value. The function value is also called a closure because it contains ("closes over") all the "free" variables in the function body - those that are not declared by the function expression itself

    In this case the function expression (num i) => addBy + i contains the free variable addBy. The function value/closure knows what that variable means - it's the parameter of the call to makeAdder that the function expression is evaluated in. Every call to makeAdder creates a new addBy variable, and every call also creates a new closure closing over that new variable.

    The closure is not just storing the value of the variable, it's referencing the variable itself. You can see that if your closure changes the value of variable.

    Example:

    /// Creates a counter function which returns a new value each call.
    ///
    /// The counter function starts at [start] and increments by [step]
    /// each time it is called.
    int Function() makeCounter([int start = 1, int step = 1]) {
      var value = start - step;
      return () => value += step;
    }
    
    main() {
      var countFrom1 = makeCounter();
      var countFast = makeCounter(1, 2);
      var countFrom100 = makeCounter(100);
    
      // Prints 1, 2, 3, 4, 5:
      for (var i = 0; i < 5; i++) print(countFrom1()); 
    
      // Prints 1, 3, 5, 7, 9:
      for (var i = 0; i < 5; i++) print(countFast()); 
    
      // Prints 100, 101, 102, 103, 104:
      for (var i = 0; i < 5; i++) print(countFrom100()); 
    
      print(countFrom1());  // Prints 6.
    }