Hi -

On Tue, 1 Aug 2006, Chad Perrin wrote:

> On Tue, Aug 01, 2006 at 09:50:23AM +0900, Logan Capaldo wrote:
>>
>> % cat closure.rb
>> def foo
>>   bar = 1
>>   lambda { puts (bar += 1) }
>> end
>>
>> baz = foo()
>>
>> baz.call
>> baz.call
>>
>> % ruby closure.rb
>> -:13: warning: don't put space before argument parentheses
>> 2
>> 3
>
> Okay.  Looks like a closure.  It looks like a closure because of the
> relationship of bar to the return-value block of code.  I've been told
> that all blocks are closures, though -- and I don't see how it's still a
> closure if the "bar = 1" is removed from foo.

It's a closure because it carries the context of its creation with it.
It doesn't matter whether that context has zero, one, or fifty local
variables; the same thing still happens.

Here's some sort of negative evidence:

  def foo
    lambda { puts bar }
  end

  bar = 1
  foo.call    # error: bar is undefined

Here, the statement "puts bar" is executed in the context of the
creation of the block (rather than the context of its execution) --
and since there's no bar there, an exception is raised.

Some subtle but possible interesting hair-splitting:

Of course, not all blocks end up getting turned into Proc objects;
some remain just syntactic constructs:

   a = 1
   [1,2,3].each {|x| puts x + a }

I guess you could debate whether that block is a closure, since it
never leaves the context where it's created -- so there's nothing
really remarkable about the fact that a is still visible inside it.
And every time you put its closureness to the test, so to speak,
you've turned it into a Proc, so technically the Proc, rather than the
block, is the closure.

(Like I said, subtle hair-splitting :-)


David

-- 
http://www.rubypowerandlight.com => Ruby/Rails training & consultancy
   ----> SEE SPECIAL DEAL FOR RUBY/RAILS USERS GROUPS! <-----
http://dablog.rubypal.com        => D[avid ]A[. ]B[lack's][ Web]log
http://www.manning.com/black     => book, Ruby for Rails
http://www.rubycentral.org       => Ruby Central, Inc.