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