I thought this was the one that worked?

D

dblack

Hi --

Hi --

# this is the sample code you provided...

a = 10
# the block is defined here but "sent" to the "each" method...
[1, 2, 3].each {|x| puts x * a }

I would say: control passes to the block. The block itself is not
represented by an object (which I think is the only quasi-objective
[ha ha] definition of "sent") in any scope other than the one in which
it was created.

(Nor, I should add, in the one in which it was created.)


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

Chad Perrin

No, I meant that my comments about whether blocks were closures was
hair-splitting. (Maybe the fact that I introduced the comments that
way looked like I was actually summing up what came before, but the
hair-splitting pronouncement ended with a colon :)

. . so it was a complete non-sequitur? Mea culpa. I assumed that
comment had something to do with your response to me. In fact, the
impression I got was that you were talking about the hair-splitting that
occurs in the differentiation between "gets something from this scope"
and "could get something from this scope", but then decided to introduce
more hair-splitting about something related -- but not strictly.

. . which makes me wonder what you were actually saying about my
points, now.
 
J

Just Another Victim of the Ambient Morality

Hi --

Hi --

# this is the sample code you provided...

a = 10
# the block is defined here but "sent" to the "each" method...
[1, 2, 3].each {|x| puts x * a }

I would say: control passes to the block. The block itself is not
represented by an object (which I think is the only quasi-objective
[ha ha] definition of "sent") in any scope other than the one in which
it was created.

(Nor, I should add, in the one in which it was created.)

...but does the definition of a closure require that the closure be an
_object?_ No, a closure is a block of code that executes outside of it's
defining scope but still has access to said scope.

Of course the control is passed to the block. How else can the block
execute? Control is passed to the block even if it were a Proc object so
this is not even a distinction, much less a meaningful one...
 
D

dblack

Hi --

. . . so it was a complete non-sequitur? Mea culpa. I assumed that
comment had something to do with your response to me. In fact, the
impression I got was that you were talking about the hair-splitting that
occurs in the differentiation between "gets something from this scope"
and "could get something from this scope", but then decided to introduce
more hair-splitting about something related -- but not strictly.

Sorry -- at this point my head is spinning. I really can't untangle
the thread itself any further.
. . . which makes me wonder what you were actually saying about my
points, now.

My main point was that you can see a closure in action in a negative
sense, in a case where there are no local variables, by doing this:

def x
lambda { puts n }
end

n = 1
x.call # undefined local variable or method `n'

You get an error because the "puts n" is being executed in the context
in which the lambda was created. If it were being executed in the
calling context, it would print 1.

If you rule out calling the lambda a closure, then you have to explain
this suspiciously closure-like behavior :)

Closures, one might say, close things out, as well as closing them in.


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

Chad Perrin

Sorry -- at this point my head is spinning. I really can't untangle
the thread itself any further.

No problem. I've had to specifically choose to abandon some of the less
promising subthreads to keep my own head from spinning like a top.

My main point was that you can see a closure in action in a negative
sense, in a case where there are no local variables, by doing this:

def x
lambda { puts n }
end

n = 1
x.call # undefined local variable or method `n'

You get an error because the "puts n" is being executed in the context
in which the lambda was created. If it were being executed in the
calling context, it would print 1.

If you rule out calling the lambda a closure, then you have to explain
this suspiciously closure-like behavior :)

This is where I thought you were saying that my statements might be
considered splitting hairs -- in differentiating between a closure with
a closure variable and a (non?)closure with a closing lexical scope that
may or may not have a closure variable.

Closures, one might say, close things out, as well as closing them in.

I certainly agree with that -- though at least one person seemed to
disagree with me on that statement. At this point, I have no
recollection of who it was or exactly what was said, though.
 
C

Chad Perrin

Hi --

Hi --

On Wed, 2 Aug 2006, Just Another Victim of the Ambient Morality wrote:

# this is the sample code you provided...

a = 10
# the block is defined here but "sent" to the "each" method...
[1, 2, 3].each {|x| puts x * a }

I would say: control passes to the block. The block itself is not
represented by an object (which I think is the only quasi-objective
[ha ha] definition of "sent") in any scope other than the one in which
it was created.

(Nor, I should add, in the one in which it was created.)

...but does the definition of a closure require that the closure be an
_object?_ No, a closure is a block of code that executes outside of it's
defining scope but still has access to said scope.

Someone correct me if I'm wrong, but . . . I got the impression that the
point being made didn't really have anything to do with objects, per se.
The use of the word "object" might have been ill-advised in terms of
keeping the conversation on-track. The impression I got from that is
that the intent was to say "the block itself is not represented,
present, whatever in any scope other than the one in which it was
created." The use of the term "object" probably arose only because
we're discussing closures within the context of Ruby.

I think.

On the other hand, I think "a block of code that executes outside of its
defining scope but still has access to said scope" works as about a
90%-complete definition of closures. All that's really missing is
something that seems to be necessarily implied by that sentence: that
the scope in question is "closed".
 
J

Just Another Victim of the Ambient Morality

Chad Perrin said:
Hi --

On Wed, 2 Aug 2006, (e-mail address removed) wrote:

Hi --

On Wed, 2 Aug 2006, Just Another Victim of the Ambient Morality wrote:

# this is the sample code you provided...

a = 10
# the block is defined here but "sent" to the "each" method...
[1, 2, 3].each {|x| puts x * a }

I would say: control passes to the block. The block itself is not
represented by an object (which I think is the only quasi-objective
[ha ha] definition of "sent") in any scope other than the one in which
it was created.

(Nor, I should add, in the one in which it was created.)

...but does the definition of a closure require that the closure be
an
_object?_ No, a closure is a block of code that executes outside of it's
defining scope but still has access to said scope.

Someone correct me if I'm wrong, but . . . I got the impression that the
point being made didn't really have anything to do with objects, per se.
The use of the word "object" might have been ill-advised in terms of
keeping the conversation on-track. The impression I got from that is
that the intent was to say "the block itself is not represented,
present, whatever in any scope other than the one in which it was
created." The use of the term "object" probably arose only because
we're discussing closures within the context of Ruby.

I know what you mean. I was afraid that he meant "object" in the
colloquial sense, rather than the programmatic sense, except that he says
"the block itself is not represented by an object," which is false if we
interpret "object" in the general sense of the word. The keyword "yield"
represents our ability to execute the block and we may even pass the block
parameters with it. Therefore, I interpreted the use of the word "object"
in the programmatic sense, since it is true that a method is not given a
block as an object unless you explicitly convert it to one...


I try to, as well, but it's hard sometimes...
 
H

Hal Fulton

Chad said:
Lexical closures *are* "real" closures. The term "closure" as it is
being bandied about is an abbreviation for "lexical closure".

I can't disagree with you. I have a friend, a very knowledgeable
person, who made a distinction there. Besides being a little
smarter than I am, he is a Perl programmer, which I am not.

I'll ask him about it sometime.


Hal
 
P

Pit Capitain

Chad said:
In any case, this can happen in Ruby:

class Foo
def bar
lambda { puts "quux" }
end
end

foo = Foo.new
bar = foo.bar

bar.call

Chad, I didn't carefully read all of this long thread because I've been
offline for a couple of days. You don't have to answer to this mail, if
it isn't relevant to you.

I had the impression that you think a block can't be called a closure if
it doesn't reference any free variables from its context, just as the
block in the example above. If I understand you correctly, then the
following two blocks should be exactly the same, shouldn't they?

blk1 = Foo.new.bar
blk2 = Foo.new.bar

But they aren't the same, as can be seen from the following code:

eval "self", blk1 # => #<Foo:0x2b851e0>
eval "self", blk2 # => #<Foo:0x2b85138>

As you can see, each block remembers at least the value of "self", when
it was created. You can get at this value even if the "self" object goes
out of scope, as you can see from my code above. There's no explicit
reference to the two instances of Foo. From this it follows (at least
for me), that each block in Ruby is a closure.

Regards,
Pit
 
J

Jacob Fugal

Maybe you know more about the implementation of blocks than I do but I
find it hard to believe that yielded blocks don't store a reference to their
environment. I mean, they were able to access it, right? How does it do
that without that reference?

The way I imagine it (I haven't looked at the C, so I could be -- and
probably am -- way off, but this is how I might make a first stab at
implementing it) is that when a method is called with a non-converted
block, that block never leaves its creation point. It is not wrapped
up in any representation, except maybe a few variables *within* (not
referring to) the calling context. When yield is encountered in the
method body, execution is bumped back up into the calling context
where the block is executed, then when the block returns we pop back
into the current context of the method. So when the block is executed,
it has access to the context where it was created because it's being
executed *in* the context where it was created.

This is obviously not what is really happening, since -- for instance
-- variables first assigned to within the block do not persist within
that blocks creating context after the block terminates. It should be
close enough, though, to show how the block can access its creating
context without needing a reference to it.
I believe that, when describing a programming language and its features,
the behaviour of the language is more important than its implementation. I
mean, the language is defined by its specification rather than some
implementation, right?

Agreed. You'll find me in the camp that claims all blocks are closure
for all practical purposes. Mostly, I was just trying to figure out
myself what David might have been referring to in his hair-splitting
comments, since I respect him a great deal and expect him to know much
more about Ruby internals than I do. :)

Jacob Fugal
 
J

Jacob Fugal

If you two agree then... why don't you improve it? It's a wiki, after
all...

The truth? Because I'd already spent to much energy and time in this
thread, I didn't have any left to spend on the wikipedia entry.
Especially since before trying to make any sort of edit based on a
belief that my understanding was more correct I'd want to do a lot
more research in authoritative sources to back up my claims.

I hope that I can find the impetus and time to do it in the near
future, however.

Jacob Fugal
 
C

Chad Perrin

Chad, I didn't carefully read all of this long thread because I've been
offline for a couple of days. You don't have to answer to this mail, if
it isn't relevant to you.

I had the impression that you think a block can't be called a closure if
it doesn't reference any free variables from its context, just as the
block in the example above. If I understand you correctly, then the
following two blocks should be exactly the same, shouldn't they?

blk1 = Foo.new.bar
blk2 = Foo.new.bar

But they aren't the same, as can be seen from the following code:

eval "self", blk1 # => #<Foo:0x2b851e0>
eval "self", blk2 # => #<Foo:0x2b85138>

As you can see, each block remembers at least the value of "self", when
it was created. You can get at this value even if the "self" object goes
out of scope, as you can see from my code above. There's no explicit
reference to the two instances of Foo. From this it follows (at least
for me), that each block in Ruby is a closure.

While I've reached a point where I think I agree that all blocks can be
called closures according to a particular valid (liberal) definition of
"closure", I don't think your explanation holds water as it stands. The
problem is that maintaining state is not the only requirement for a
closure. In fact, according to the interpretation of a closure's
definition that allows all blocks in Ruby to be closures, a closure need
not maintain (meaningful) state at all. Besides, I think you're
pointing out memory addresses for those objects, not something internal
to them. Please correct me if I'm wrong.
 
J

Jacob Fugal

If I understand you correctly, then the
following two blocks should be exactly the same, shouldn't they?

blk1 = Foo.new.bar
blk2 = Foo.new.bar

But they aren't the same, as can be seen from the following code:

eval "self", blk1 # => #<Foo:0x2b851e0>
eval "self", blk2 # => #<Foo:0x2b85138>

As you can see, each block remembers at least the value of "self", when
it was created. You can get at this value even if the "self" object goes
out of scope, as you can see from my code above. There's no explicit
reference to the two instances of Foo. From this it follows (at least
for me), that each block in Ruby is a closure.
[snip]
I think you're
pointing out memory addresses for those objects, not something internal
to them. Please correct me if I'm wrong.

self is not just a memory address (well, not any more than any other
object reference). You're seeing the memory address because that's the
default #inspect output for an object, but it's not really relevant
here. self is an object reference just like any other variable would
be. Let's replace the contents of the evals with a method call
instead:

# using the same definition of Foo as referenced earlier
foo1, foo2 = Foo.new, Foo.new
foo1.object_id # => 1742734
foo2.object_id # => 1742684

blk1, blk2 = foo1.bar, foo2.bar
eval "object_id", blk1 # => 1742734
eval "object_id", blk2 # => 1742684

I also captured the Foo objects themselves so we can see that the
object_id method call is being sent to the foo object rather than the
block itself.

Jacob Fugal
 
C

Chad Perrin

self is not just a memory address (well, not any more than any other
object reference). You're seeing the memory address because that's the
default #inspect output for an object, but it's not really relevant
here. self is an object reference just like any other variable would
be. Let's replace the contents of the evals with a method call
instead:

# using the same definition of Foo as referenced earlier
foo1, foo2 = Foo.new, Foo.new
foo1.object_id # => 1742734
foo2.object_id # => 1742684

blk1, blk2 = foo1.bar, foo2.bar
eval "object_id", blk1 # => 1742734
eval "object_id", blk2 # => 1742684

I also captured the Foo objects themselves so we can see that the
object_id method call is being sent to the foo object rather than the
block itself.

Are we sure, though, that we're not just looking at a number (associated
with that instance) that's stored in a hash table external to the
object?
 
J

Jacob Fugal

Are we sure, though, that we're not just looking at a number (associated
with that instance) that's stored in a hash table external to the
object?

Actually, object_id is calculated from the reference itself.
Simplified, it's pretty similar to the memory reference itself. But
the point is, while the memory reference may be the source of the
value, we're retrieving it through a method call. The fact that I'm
making a method call implies that we have a reference to an object
call that method against. The choice of object_id as that method is
just convenience to show that the objects referred to are at once
unique from each other, and identical to the source objects.

Jacob Fugal
 
C

Chad Perrin

Actually, object_id is calculated from the reference itself.
Simplified, it's pretty similar to the memory reference itself. But
the point is, while the memory reference may be the source of the
value, we're retrieving it through a method call. The fact that I'm
making a method call implies that we have a reference to an object
call that method against. The choice of object_id as that method is
just convenience to show that the objects referred to are at once
unique from each other, and identical to the source objects.

That sounds plausible. Okay, I believe you. Heh.

Thanks for the effort in explaining it.
 

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,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top