Ruby's scoping rules with respect to iterators are kinda controversial
even by the standards of other languages with lexical scoping. (In
Lisp you'd be able to look at the parentheses and know exactly what's
in scope where! :) There's been talk of changing them but I'm not 1.9-
savvy enough to know if any of that has happened yet.
The reason is that when iterators were conceived, they were thought of
as abbreviated, glorified "for" loops, but it soon became apparent
that having an easy way to pass a block to a method allowed you to do
all kinds of wonderful unforeseen things, and they became a major
feature of Ruby -- but there were some historical artifacts regarding
scoping, from their more humble origins, that seem peculiar in
retrospect.
That's what I vaguely remember hearing about it anyway. I could be
wrong and welcome correction!
On Jul 27, 2009, at 5:42 AM, Cecil Coupe wrote:
Yet another reminder why Lisp scoping rules and my feeble lexical
brain
don't mesh. I have no opinion as to why or if it's a good thing (Tm)
but
it'll burn us old school non Lispers.
On Mon, 2009-07-27 at 05:15 -0400, MenTaLguY wrote:
I wasn't terribly clear. Let me rephrase -- if you do this:
urls.each do |url|
link url, :click => Proc.new { window { image url } }
end
Then every link will open the same image url (since all the created
Procs reference the same variable, which ends up with the same final
value). However, if you do this:
def make_image_callback(url)
Proc.new { window { image url } }
end
image_urls.each do |image_url|
link image_url, :click => make_image_callback(image_url)
end
Then the links should open the correct images, since each call to
make_image_callback establishes up a separate context for a Proc
inside
to capture, rather than all the Procs sharing the same context and
variables.
You could also do the call to link itself inside the helper method
(as I
did in my earlier email), but you don't need to.
-mental