From: Jacob Fugal Date: 2006-08-02T01:28:45+09:00 Subject: Re: I thought this was the one that worked? On 8/1/06, Chad Perrin wrote: > On Tue, Aug 01, 2006 at 12:05:50PM +0900, dblack@wobblini.net wrote: > > 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. > > It sounds like what you're saying is that the lexical scope of the code > block (proc/lambda/blah) is what makes it a closure, and not the > connection with, and OOPish protection/encapsulation of, something that > started outside the code block and went out of scope externally to the > code block. No, what he's saying is that what makes it a closure is exactly that form of encapsulation (capture, I would say) of its surrounding *environment*. I think that's the key distinction here. You seem set in the belief that a closure is around a specific variable or group of variables. If those variables don't exist, then the closure must not exist. Unfortunately the current definition on Wikipedia (which I consider useful, but not authoritative) reflects that type of thinking. But the definition I learned in the University, have seen in multiple CS theory texts and to which David is referring here is that the closure is around an *environment*, regardless of what variables from that environment may or may not exist and/or be used. So even if the environment were empty, or the lambda/proc didn't reference any variables from the environment, the lambda/proc is still capturing that environment, forming a closure around it. Even then, an empty environment can't exist in Ruby. There's always at least one "variable" in the environment that will be accessible in the closure: self. Take the following example: class Foo def bar lambda{ baz } end end foo = Foo.new bar = foo.bar class << foo def baz puts "quux" end end bar.call # prints "quux" It can't be argued that the definition of baz is being captured from its surrounding environment; it didn't exist when the lambda was created, and even when it was defined, it was in a different environment. What the lambda formed a closure around was the environment. Included in that environment was self. When the interpreter sees "baz", it sends (essentially, there's of course permission checks and such) "baz" to the self defined in the lambda's environment; that is, the self captured by the closure. The method lookup chain on that object can then find the definition of baz we put into the singleton class for foo. So the environment is never empty. The only remaining argument would be something like "If a lambda/proc doesn't use any values from it's environment (even self, so no receiverless method calls), then it's not a closure." I say it would be a closure anyways, since the captured environment is still there, still taking up memory, still accessible, only unused. > [snip] > it would mean that absolutely any unnamed subroutine passed by reference in > Perl is a closure. In fact, by the implied definition of a closure that > produces, this is a closure in Perl: > > sub bar { > sub { print "Hello world!\n" }; > } > > $foo = bar(); > > $foo->(); From what I learned in my CS courses and my knowledge of how perls scopes work, that *is* a closure. Simply because the facilities provided by a construct aren't used doesn't make the construct cease to be... > That's the equivalent of this, in Ruby: > > def bar > lambda { puts "Hello world!" } > end > > foo = bar > > foo.call Again, also a closure. But this one even more specifically: in the method call to puts, you're using the value of self captured in the environment closed over by the lambda. Jacob Fugal