[parenscript-devel] Closures inside loops: when should values be captured?

Vladimir Sedach vsedach at gmail.com
Fri Apr 6 23:52:58 UTC 2012


That's the correct behavior because you're closing over the same
binding of i in all iterations. This equivalent CL code:

(let ((foo (make-array 3))
               (i 0))
           (loop while (< i 3) do
             (setf (aref foo i) (lambda () i))
             (incf i))
           (funcall #'princ (funcall (aref foo 0)))
           (funcall #'princ (funcall (aref foo 1)))
           (funcall #'princ (funcall (aref foo 2))))

Also does 3 3 3

Vladimir

On Thu, Apr 5, 2012 at 7:20 PM, Daniel Gackle <danielgackle at gmail.com> wrote:
> 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
>
>
> _______________________________________________
> parenscript-devel mailing list
> parenscript-devel at common-lisp.net
> http://lists.common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel
>




More information about the parenscript-devel mailing list