ceylon / ceylon-js

DEPRECATED
Apache License 2.0
54 stars 9 forks source link

Weird capture bug with callables #526

Closed chochos closed 9 years ago

chochos commented 9 years ago

I found this while testing the SDK, particularly ceylon.promise. This code:

  variable String() task = () {
    return "task";
  };
  value t=[print,print,print];
  for (c in t) {
    String() f=task;
    task=() {
      print("In loop c=``c``");
      value s=f();
      c(s);
      return s;
    };
  }
  print("Finally the task is ``task``");
  task();

prints this, then breaks:

Finally the task is ceylon.language::JsCallable@1 In loop c=finished In loop c=finished In loop c=finished

It's trying to use finished as a function. But in every iteration, c should be a new function. Somehow the current item for the loop is not captured in the function created in every iteration.

FroMage commented 9 years ago

What gets captured or not is a long story in every language. In this case c is defined once in the loop and overridden at each iteration, so there's only a single binding that can be captured and it will hold the last value written to it after the loop is done. That's pretty well-defined in JS, and for loops and capture are a common gotcha in many languages. That's not the case in LISP because there's no iteration: it's only iteration using recursion, so you effectivement get an brand new environment at each iteration, which you can capture and is immutable.