When a closure is created inside a loop, PS wraps the closed-over variables using a JS WITH statement to ensure that each closure will get the values that existed at the time it was created. Here's an example from Vladimir's email to the list from Jan 30, 2011:
(let ((foo (make-array 3))) (dotimes (i 3) (setf (aref foo i) (lambda () i))) (funcall (@ console log) (funcall (aref foo 0))) (funcall (@ console log) (funcall (aref foo 1))) (funcall (@ console log) (funcall (aref foo 2))))
This correctly prints 0,1,2 to the console. If PS didn't do this extra work and relied on JS scoping, the output would be 3,3,3 which is obviously (or at least arguably) incorrect.
But this doesn't happen for variables declared prior to the loop form. Here is the above example written to use WHILE rather than DOTIMES:
(let ((foo (make-array 3)) (i 0)) (while (< i 3) (setf (aref foo i) (lambda () i)) (incf i)) (funcall (@ console log) (funcall (aref foo 0))) (funcall (@ console log) (funcall (aref foo 1))) (funcall (@ console log) (funcall (aref foo 2))))
It prints 3,3,3. Of course, probably no one would use WHILE to write this particular loop, but it's easy to see how one might run in to the problem. In particular, the PS LOOP macro generates WHILE forms for many standard kinds of loop. That is how I ran across this issue: I have a LOOP form that builds a table of closures for asynchronous callback in a Node.js program and by the time these closures are called back, they no longer have their expected data - for exactly the same reason as the above example prints 3,3,3.
My first question is: is this a bug? That is, if it's incorrect for the first loop to print 3,3,3, is it also incorrect for the second loop to do so?
Daniel