[parenscript-devel] Closures inside loops: when should values be captured?
Daniel Gackle
danielgackle at gmail.com
Sat Apr 7 00:00:39 UTC 2012
Thanks. I noticed the same thing about CL, but wasn't clear on the
principle. Now I think I understand. The salient question is: was the
variable declared inside the loop? If it was, there's an implicit
request to get a new binding each time the loop executes. If it
wasn't, all closures over the variable will share the same binding.
On Fri, Apr 6, 2012 at 5:52 PM, Vladimir Sedach <vsedach at gmail.com> wrote:
> 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
> >
>
> _______________________________________________
> parenscript-devel mailing list
> parenscript-devel at common-lisp.net
> http://lists.common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mailman.common-lisp.net/pipermail/parenscript-devel/attachments/20120406/c636c9fa/attachment.html>
More information about the parenscript-devel
mailing list