I thought this was the one that worked?

E

Eric Armstrong

I swear to the heavens that it was an innocent question?
(But I look forward to a clear differentiation
between closures and blocks from the thread that
resulted.)

class, **def**, and module introduce a new scope
without closing over their enclosing scope.
That was the shift I needed in my mental model.
Thanks much. I expected that behavior from class
and module. I am quite surprised that it is true
for def, as well.

That surprise leads me to ask: Why?
What is it that made that a good idea?

thanks, all
eric
 
L

Logan Capaldo

How's this?:

Closure
A "closure" is an expression (typically a function) that can
have
free variables together with an environment that binds those
variables (that "closes" the expression).

In ruby this environment always exists for a block regardless of the
presence of free variables, since the declaration of the variables
that are free in the block can be added after (in time) the creation
of the closure.
I found it on this page:

http://jibbering.com/faq/faq_notes/closures.html

I also found this:

http://www.perl.com/pub/a/2002/05/29/closure.html



My understanding is that the vehicle is a car, and the use of it is a
drive (to the country, or whatever). Similarly, a block of code that
can be passed around like a first-class member is a block, or
lambda, or
whatever you want to call it today: if you pass it to a function as an
argument, it's a callback, and if you lexically close it, it's a
closure.



I suppose that's possible, but I really don't think so. Do you have a
formal definition of a closure that specifically contradicts my
understanding?

Your definition is consistent with what happens in ruby, it just
happens to be difficult to demonstrate with a run of the mill ruby
program. Ruby will never say "Oh this block doesn't reference any
free variables in it's enclosing scope, I will just create an
anonymous function instead of a closure." It will always create the
closure in anticipation of possible changes to the enclosing
environment.
 
L

Logan Capaldo

I swear to the heavens that it was an innocent question?
(But I look forward to a clear differentiation
between closures and blocks from the thread that
resulted.)


That was the shift I needed in my mental model.
Thanks much. I expected that behavior from class
and module. I am quite surprised that it is true
for def, as well.

That surprise leads me to ask: Why?
What is it that made that a good idea?

thanks, all
eric

I imagine it was to avoid having to declare local variables. e.g.:

a = 1

def add_two
a = 2
return a + n
end


... hundred of lines of code later ...

def b
puts a
end

Now I imagine when our hypothetical programmer wrote b he expected it
to always print the value of the top-level a.

OTOH when he wrote add_two he was expecting a to behave as a local
variable.

If defs were closures, we'd have to write

def foo
my a
or
local a
or
declare a
or
var a
end

etc. to make sure we weren't in in-advertantly using an effectively
"global" variable
 
C

Chad Perrin

It's still a closure.

Like I said it's hard to give you an example, but ruby creates a
closure for a block regardless. That lambda still has a reference to
the enclosing scope of foo, even if their are no variables there. Ok
I came up with a good one:

% cat closure2.rb
class A
def initialize
@a = 1
end

def foo
lambda { puts @a }
end

def set_var(val)
@a = val
end
end

a = A.new
baz = a.foo
baz.call

a.set_var( "Hello" )

baz.call

% ruby closure2.rb
1
Hello

That block, "lambda { puts @a }", is still making reference to a
variable that was explicitly declared to a scope outside itself. Let's
try this:

def foo
bar = 0
lambda { bar += 1; puts bar; }
end

baz = foo

There's a closure. Invoking baz.call will output an iterated value.
Now have a look at this:

def foo
puts "Stuff!"
lambda { puts "Junk!" }
end

bar = foo

. . then tell me whether it's still a closure -- and why, despite the
lack of reference within the lambda block to anything outside of it.
 
C

Chad Perrin

In ruby this environment always exists for a block regardless of the
presence of free variables, since the declaration of the variables
that are free in the block can be added after (in time) the creation
of the closure.

I think that depends on what you mean by "creation of the closure" in
this case. Are you talking about the code used to create it, or the
assignment of the return value of the closure's enclosing scope to a
variable?
 
L

Logan Capaldo

I think that depends on what you mean by "creation of the closure" in
this case. Are you talking about the code used to create it, or the
assignment of the return value of the closure's enclosing scope to a
variable?

I'm talking about what happens inside the ruby interpreter when it
sees that code. As far as ruby is concerned, it doesn't know how to
make a block that isn't a "closure". The same code path gets followed
whether ruby sees

def foo
a = 1
lambda { ... a ... }
end

or

def foo
lambda { ... }
end

All the "closure bookkeeping" is done whenever you create a block. No
extra bookkeeping is done whether or not you take advantage of the
fact that you have a "closure".


 
J

Just Another Victim of the Ambient Morality

Chad Perrin said:
I'm hoping that demonstrating how it does or does not work in Perl will
make it clear what I'm talking about, based on similar syntax between
the languages, so that I can find out what does and does not work in
Ruby. Duh?

Well, I suppose the question can be directed only to those who know Perl
but the two languages seem to be sufficiently different (despite Ruby's Perl
origins) that your analogies are hard to make or make clear...

I know there's a difference, thanks. The problem is that nobody seems
to be addressing the fact that for a proper closure, as I understand it,
the closure variable has to go out of scope while the block of code does
not. If Ruby blocks do something automagical to make variables declared
within them go out of scope while the block is still in scope, I'd like
to know. If there's some other way to "close" the block's data while
the block is still available, I'd like to know that, too.

I'm having trouble parsing your sentences here so I am going to pretend
that I understand you and you can tell me where I'm going wrong, okay?

def some_method_as_function
# code block goes here but
# in the Ruby world, this is not a "block..."
end

while some_condition
# code block goes here but
# in the Ruby world, this is not a "block..."
end


These are Ruby blocks:


[1, 2, 3].each do |i|
# this is a Ruby block and
# this is a closure
end

So explain how it is a closure. Please.

Okay, I think I can do this much...

I'm going to implement the "each" method of an array using the passed in
block, which is a closure, using the array reference operator "[]" and the
size method...


local_variable = 2

class Array
# local_variable is outside this scope..

def each
# local_variable is also outside this scope...

i = 0
while i < self.size

# call the passed in block which is also a closure...
yeild self

i += 1
end
end
end

array = [1, 2, 3]

array.each do |i|
# we have access to local_variable even though this
# will be executed far away from local_variable's scope
# because this block of code is a closure...

puts local_variable * i
end

Am I to assume that some_local_variable is going out of scope outside of
the lambda declaration at some point, to create that closure?

Yes, you are. It didn't occur to me to demonstrate that it was a
closure, only how to make blocks that are closures in Ruby. I hope the
previous paragraph demonstrated what you wanted to know...

Yes. Are you just failing to explain how these things are closures, or
do you not know what a closure is? You keep telling me blocks are
closures somehow, but you're not explaining how. Saying it doesn't make
it so. Please explain what I'm missing.

I _think_ I know what a closure is, as long as Wikipedia and all Ruby
tutorials haven't conspired to lie to me. Again, it didn't occur to me show
you that they are closures. I was only trying to show you what will make a
closure...
So, are these closures, as you understand them? How is your
understanding different from mine?
 
C

Chad Perrin

I'm talking about what happens inside the ruby interpreter when it
sees that code. As far as ruby is concerned, it doesn't know how to
make a block that isn't a "closure". The same code path gets followed
whether ruby sees

def foo
a = 1
lambda { ... a ... }
end

or

def foo
lambda { ... }
end

All the "closure bookkeeping" is done whenever you create a block. No
extra bookkeeping is done whether or not you take advantage of the
fact that you have a "closure".

Arrrrrrgh. We're talking past one another. I can see where at least
some of the disconnect is occurring, but I don't seem to be able to get
across to you what you're not saying so that you'll explain it.

I give up for now. I'll just see if I can learn what's actually going
on with blocks and closures in Ruby from some other source.
 
C

Chad Perrin

[ snip ]
I _think_ I know what a closure is, as long as Wikipedia and all Ruby
tutorials haven't conspired to lie to me. Again, it didn't occur to me show
you that they are closures. I was only trying to show you what will make a
closure...
So, are these closures, as you understand them? How is your
understanding different from mine?

There was some stuff to digest there, and I'll be digesting it. As for
what I didn't snip, I'll try explaining a closure (as I understand it)
in different terms:

There is a variable. There is a (something we'll call "lambda"). The
lambda uses the variable. The variable is in a scope outside of the
lambda's scope, but available to the lambda. The variable's original
scope "closes", thus eliminating the variable for purposes of anything
else in the program other than the lambda, thus "closing" the code in
the lambda -- thus the term "closure". It produces circumstances that
object oriented programmers would recognize as "protection" and
"encapsulation".

How does that mesh with your take on it?
 
C

Chad Perrin

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. I guess that makes a certain amount of sense, but that
seems like an absurdly broad definition of a closure. For one thing, 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->();

(Yes, I find the dereferencing syntax in Perl to be ugly and cumbersome
too, but that's beside the point.)

That's the equivalent of this, in Ruby:

def bar
lambda { puts "Hello world!" }
end

foo = bar

foo.call

(".call" is much prettier than "->()")

Would you say those are both closures?
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 :)

Let's assume for the moment that we'll split the hair on the side of
calling it a closure, and focus on the presence or absence of a variable
declared outside the lambda's scope. See my above examples. I'm not
saying that's where I'd split the hair, but it's not where I want to
focus right now.
 
C

Chad Perrin

I imagine it was to avoid having to declare local variables. e.g.:

a = 1

def add_two
a = 2
return a + n
end


... hundred of lines of code later ...

def b
puts a
end

Now I imagine when our hypothetical programmer wrote b he expected it
to always print the value of the top-level a.

OTOH when he wrote add_two he was expecting a to behave as a local
variable.

This is one of the reasons that explicit scoping declarations are
generally a good idea: testing code with explicit lexical scoping
declarations will quickly tell you exactly what you screwed up, and
using local dynamic declarations will actually do what you surmise the
hypothetical programmer must have assumed. Autovivification is great,
as long as you use it with conscious intent for good reasons rather than
just because you're lazy.
 
J

Just Another Victim of the Ambient Morality

Chad Perrin said:
[ snip ]
I _think_ I know what a closure is, as long as Wikipedia and all Ruby
tutorials haven't conspired to lie to me. Again, it didn't occur to me
show
you that they are closures. I was only trying to show you what will make
a
closure...
So, are these closures, as you understand them? How is your
understanding different from mine?

There was some stuff to digest there, and I'll be digesting it. As for
what I didn't snip, I'll try explaining a closure (as I understand it)
in different terms:

There is a variable. There is a (something we'll call "lambda"). The
lambda uses the variable. The variable is in a scope outside of the
lambda's scope, but available to the lambda. The variable's original
scope "closes", thus eliminating the variable for purposes of anything
else in the program other than the lambda, thus "closing" the code in
the lambda -- thus the term "closure". It produces circumstances that
object oriented programmers would recognize as "protection" and
"encapsulation".

How does that mesh with your take on it?

Well, I think that meshes just fine with my take on it...
To tell you the truth, I didn't expect you to ask me what my
understanding of a closure is because I thought I had already demonstrated
it with the code sample I gave. Of course, you're busy digesting that and I
appreciate it. It means you're actually trying to understand me (rather
than just arguing at me. Something that happens all too often...).
If I may be so bold, I think that, perhaps, blocks don't look like
closures to you because you don't realize that methods that take blocks,
like "each," "inject," "collect," etc.. are methods (member functions, if
you're a C++ guy) and not arbitrary language constructs, like "if," "while,"
"for," etc...

Now that I think about it, this whole argument can be settled with one
simple question. If you doubt that all blocks are closures then show us a
counter-example. Show us a "block" that is not a closure and I will show
you how it's not a block...
 
J

Just Another Victim of the Ambient Morality

Chad Perrin said:
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. I guess that makes a certain amount of sense, but that
seems like an absurdly broad definition of a closure. For one thing, 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:

This seriously sounds like an "if a tree falls in the forest, does it
make a sound?" kind of situation. In other words, it's a semantic
argument...

sub bar {
sub { print "Hello world!\n" };
}

$foo = bar();

$foo->();

(Yes, I find the dereferencing syntax in Perl to be ugly and cumbersome
too, but that's beside the point.)

That's the equivalent of this, in Ruby:

def bar
lambda { puts "Hello world!" }
end

foo = bar

foo.call

(".call" is much prettier than "->()")

Would you say those are both closures?

Personally, I would call them closures, if they have access to their
environments.
Perhaps we can agree to call a closure a block of code that has the
_ability_ to access variables of their enclosing scope, rather than strictly
requiring that they take advantage of this ability?
 
J

Just Another Victim of the Ambient Morality

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.

I would debate that it _is_ a closure because, although it's defined
where its context is, that's irrelevant. What matters is that the block is
passed into the "each" method of the Array class and is executed there,
where "a" is not visible. Thus, the block was executed outside of the scope
of "a" while still having access to it. How is this possible? It's
possible because the block that was passed in is a closure...
QED.
 
C

Chad Perrin

Well, I think that meshes just fine with my take on it...
To tell you the truth, I didn't expect you to ask me what my
understanding of a closure is because I thought I had already demonstrated
it with the code sample I gave. Of course, you're busy digesting that and I
appreciate it. It means you're actually trying to understand me (rather
than just arguing at me. Something that happens all too often...).
If I may be so bold, I think that, perhaps, blocks don't look like
closures to you because you don't realize that methods that take blocks,
like "each," "inject," "collect," etc.. are methods (member functions, if
you're a C++ guy) and not arbitrary language constructs, like "if," "while,"
"for," etc...

I'm not exactly a C++ guy. I suppose I'm more of a Perl guy than
anything else, judging by my familiarity with languages and the
assumption of a lack of loathing (I'm as familiar with PHP as with Perl,
but I don't like it very much, for instance). I am familiar with many
of the idioms and much of the semantic and syntactic theory of a lot of
languages, even if I don't use them much, though. The dangers of doing
consulting and industry analysis for money. . . .

Now that I think about it, this whole argument can be settled with one
simple question. If you doubt that all blocks are closures then show us a
counter-example. Show us a "block" that is not a closure and I will show
you how it's not a block...

Is this a closure? You tell me (and tell me how, if it is):

array.each do ||
puts "Hello world!"
end
 
C

Chad Perrin

This seriously sounds like an "if a tree falls in the forest, does it
make a sound?" kind of situation. In other words, it's a semantic
argument...

Okay, let's translate that question into the terms we're actually
discussing.

1. If a tree falls in the forest, and there's no one around to hear
it, does it still make a sound?

2. If a lambda has the ability to access its context, but there isn't
any context to access, is it still a closure?

Personally, I would call them closures, if they have access to their
environments.
Perhaps we can agree to call a closure a block of code that has the
_ability_ to access variables of their enclosing scope, rather than strictly
requiring that they take advantage of this ability?

Not yet. See above, re: blocks falling in a forest.

I'm beginning to think the question of whether it's actually a closure
really IS a question for a programming koan, after all. If so, I'm glad
we've at least narrowed the discussion down to this point at last.

It'd be pretty neat to be responsible for the creation of a new
programming koan, anyway. I'm going to go add this to my sig rotation
right now.
 
X

Xavier Noria

2. If a lambda has the ability to access its context, but there
isn't
any context to access, is it still a closure?

Hahaha, in the next conference someone should bring a stick and hit
suddenly people asking that with energy.

-- fxn
 
D

dblack

Hi --

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.

I would debate that it _is_ a closure because, although it's defined
where its context is, that's irrelevant. What matters is that the block is
passed into the "each" method of the Array class and is executed there,
where "a" is not visible. Thus, the block was executed outside of the scope
of "a" while still having access to it. How is this possible? It's
possible because the block that was passed in is a closure...
QED.

It's not exactly passed to the method, though. You can capture it in
the method -- in which case, it becomes a Proc object, and then
there's no issue (hair-splitting or otherwise) about its being a
closure.

If you don't capture it, you can yield to it -- but then you're
yielding to the block, not calling a Proc object derived from the
block.

It comes down to the fact that blocks are syntactic constructs, while
Procs are first-class objects.


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.
 
D

dblack

Hi --

I'm not exactly a C++ guy. I suppose I'm more of a Perl guy than
anything else, judging by my familiarity with languages and the
assumption of a lack of loathing (I'm as familiar with PHP as with Perl,
but I don't like it very much, for instance). I am familiar with many
of the idioms and much of the semantic and syntactic theory of a lot of
languages, even if I don't use them much, though. The dangers of doing
consulting and industry analysis for money. . . .



Is this a closure? You tell me (and tell me how, if it is):

array.each do ||

You don't need the || (and hopefully that will continue to be the case
forever, though there have been some troubling allusions to the
possbiility of having it mean something some day...).
puts "Hello world!"
end

See my last couple of posts about blocks vs. Procs. To which I'll
add: it's not *quite* possible, I think, to argue that a block isn't a
closure, because it does have its own scope -- so it's not like
arguing that, say, an if statement is a closure.


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.
 
D

dblack

Hi --

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 makes something a closure, as I understand it, is that it
carries the context of its creation with it. Also, there's actually a
difference between a block on the one hand, and a Proc or lambda on
the other. (See my last couple of posts.)
I guess that makes a certain amount of sense, but that
seems like an absurdly broad definition of a closure. For one thing, 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->();

(Yes, I find the dereferencing syntax in Perl to be ugly and cumbersome
too, but that's beside the point.)

That's the equivalent of this, in Ruby:

def bar
lambda { puts "Hello world!" }
end

foo = bar

foo.call

(".call" is much prettier than "->()")

Would you say those are both closures?

I agree with Logan that the presence or absence of actual variables
isn't what makes something a closure. Rather, it's a matter of what's
actually happening in the language. To me, the distinction you're
describing is sort of like having one class to represent arrays with
one or more elements, and another class to represent empty arrays.
(See also my example with the non-existent bar variable, which
demonstrates that lambdas created in a given context are executed in
that context, with or without local variables.)

I think of a closure as a kind of suitcase: you pack it in one place,
and unpack it somewhere else. Even if it's empty, though, it's still
a suitcase.

Another way to look at it is this: if you decide that the lambda in
your example above is not a closure, then you have to come up with
separate explanations for everything it does that is closure-like.
If you look at it as a closure, however, there's nothing unaccounted
for.


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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,774
Messages
2,569,596
Members
45,144
Latest member
KetoBaseReviews
Top