Forum: Ruby What's the difference between copying and sharing in closure

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Ca0b18ec9e11dc777b2b8084fe5d5f90?d=identicon&s=25 Sam Kong (Guest)
on 2006-02-07 18:41
(Received via mailing list)
Hello!

I read an interview article with matz about closure.
(http://www.artima.com/intv/closures2.html)

He mentioned that Ruby's closure is a real closure like Lisp.
Local variables are shared between a method and a closure.

<snip>
local variables are shared between the closure and the method. It's a
real closure. It's not just a copy.
....
Yes, and that sharing allows you to do some interesting code demos, but
I think it's not that useful in the daily lives of programmers. It
doesn't matter that much. The plain copy, like it's done in Java's
inner classes for example, works in most cases. But in Ruby closures, I
wanted to respect the Lisp culture
</snip>


Can somebody help me understand what he meant?
Closures in other languages are different from Ruby?
And if possible, I want to see the *interesting code demos".

Thanks.

Sam
430ea1cba106cc65b7687d66e9df4f06?d=identicon&s=25 David Vallner (Guest)
on 2006-02-07 19:19
(Received via mailing list)
DÅ?a Utorok 07 Február 2006 18:38 Sam Kong napísal:
> real closure. It's not just a copy.
> Closures in other languages are different from Ruby?
> And if possible, I want to see the *interesting code demos".
>
> Thanks.
>
> Sam

A "closure" in Java is somewhat used when doing quick GUI hacks:

	class FooButton {
		private final String foo = "FOO";
		{
			this.addActionListener(new ActionListener() {
				public actionPerformer(ActionEvent e) {
					// Pop up a message box saying "FOO" when the button is pressed.
					JOptionPane.showMessageDialog(null, foo);
			});
		}
	}

You can only use variables declared as final inside the anonymous inner
class
(the ActionListener); what will be accessible inside the inner class
code is
a copy of the reference to foo.

That means you can't assign another String to the variable foo from
inside the
"closure" code. Java goes overkill here by making sure you can't
possibly
reassign something to foo at all after initialization.

Contrast this to Ruby:

	def do_yield()
		yield
	end

	foo = "FOO"
	do_yield() {
		foo = "BAR"
	}
	puts foo # Outputs "BAR".

Which means you can assign to local variables in the closure's lexical
scope
from inside the closure.

This is usually only really useful when implementing custom control
structures
- the #loop method comes to mind. The Smalltalk language made use of
this
extensively. Usually, it's much more cleaner and readable to structure
your
code so any result of the computation performed inside the block is
returned
as (part of) the result of the method you pass a block to - for example
using
#collect, #select, or #inject than using #each as you'd use a loop
construct
in for example Java.

David Vallner
Ede7f0028025fb88b47dda1a8c38be42?d=identicon&s=25 Lionel Thiry (Guest)
on 2006-02-08 17:34
(Received via mailing list)
Sam Kong a écrit :
> real closure. It's not just a copy.
> Closures in other languages are different from Ruby?
> And if possible, I want to see the *interesting code demos".
>
> Thanks.
>
> Sam
>

Sharing closure in ruby:

class A
 attr_accessor :a
 def initialize
  @a = "value"
 end
 def test
  proc { @a }
 end
end

a = A.new
block = a.test
puts block.call # "value"
a.a = "changed value"
puts block.call # "changed value"


Copying closure in python:

class A:
	def __init__(self):
		self.a = "value"
	def test(self):
		return lambda a=self.a : a

a = A()
block = a.test
print block() # "value"
a.a = "changed value"
print block() # "value"


--
Lionel Thiry

Personal web site: http://users.skynet.be/lthiry/
10d4acbfdaccb4eee687a428ca00a5d8?d=identicon&s=25 Jim Weirich (weirich)
on 2006-02-08 18:06
Sam Kong wrote:
> Can somebody help me understand what he meant?
> Closures in other languages are different from Ruby?
> And if possible, I want to see the *interesting code demos".

Here's an example that happens regularly in testing scenarios:

  def test_callback_gets_called
    cb_called = false
    widget = Widget.new
    widget.register_callback { cb_called = true }
    widget.do_something
    assert_true cb_called, "Expected the callback to be called"
  end

Without 'full' closures that can modify the bindings, one would have to
turn cb_called into an object that could be modified, (e.g. an array):

  def test_callback_gets_called
    cb_called = [ false ]
    widget = Widget.new
    widget.register_callback { cb_called[0] = true }
    widget.do_something
    assert_true cb_called[0], "Expected the callback to be called"
  end

--
-- Jim Weirich
D63c268960051bc17a310aa29fffd979?d=identicon&s=25 Dave Cantrell (Guest)
on 2006-05-03 18:56
(Received via mailing list)
> 	puts foo # Outputs "BAR".
>
> Which means you can assign to local variables in the closure's lexical scope
> from inside the closure.

Question: How is the above different from, say in pseudo code:

   function do_something(in)
     foo = in
   end function

   foo = "FOO"
   do_something("BAR")

   print foo  # should still output "BAR", right?

Other than the fact that you can create the block logic at call time
rather than at declaration time, what is the difference in how the two
scopes are handled? In both the Ruby example and the pseudo-code case,
the variable foo is a globally-scoped variable (well, for that code
snippet anyway) and therefore should be accessible to any function that
is subordinate to it.

After reading the example above I was led to try something similar. I'm
definitely a Ruby Nuby (I had to research the IO routines to pad the
code for this e-mail) so I had to fiddle with the variable scoping for a
while to get it to work. It wasn't until I managed to get the variable
assignment into the right place that I got something other than nil or a
proc object.

But in the end, writing this helped me better understand the way Ruby
shares variables in closures. Though I'm still confused as to how it's
truly different from regular scoping rules.

   class MethodList
     def initialize
       @methods = []
     end

     def add(&block)
       @methods << block
     end

     def run(param)
       i = param
       @methods.each { |m| i = m.call(i) }
       i
     end
   end

   m = MethodList.new
   m.add { |x| x + 1 }
   m.add { |x| x + 1 }
   m.add { |x| x + 1 }

   puts m.run(1)


Which, of course, outputs 4. What tripped me up was getting the hang of
the proper way to update the i variable and the proper way to output the
result. I first tried to have the puts in each of the m.add {} blocks --
then I realized I'm overdue for sleep. Doh. Can you see me getting the
hang of blocks? :)

Any clarification greatly appreciated.

Thanks,
-dave
430ea1cba106cc65b7687d66e9df4f06?d=identicon&s=25 David Vallner (Guest)
on 2006-08-03 13:44
(Received via mailing list)
DÅ?a Streda 08 Február 2006 05:57 Dave Cantrell napísal:
> > 	puts foo # Outputs "BAR".
>    foo = "FOO"
>    do_something("BAR")
>
>    print foo  # should still output "BAR", right?
>

Wrong. Presuming the pseudocode behaves like ruby with respect to
scoping
rules, the "foo = in" in #do_something creates a new local variable foo
and
assigns "BAR" to it.

You can of course share a global variable, in Ruby: $foo. The difference
with
using a closure is that you share a -local- variable from the enclosing
scope. For a (very contrived) example of where the difference shows:

	def do_yield
		yield
	end

	foo = "FOO" # Local variable in the toplevel scope.

	def change_and_print_a_foo # *Groan*
		# A new local variable in the scope of the method. The toplevel
		# variable of the same name cannot be accessed here.
		foo = "BAR"
		puts foo # Outputs BAR.

		do_yield {
			foo = "QUUX"
		}

		puts foo # Outputs QUUX.
	end

	change_and_print_a_foo

	puts foo # Outputs FOO.

This example isn't supposed to demonstrate the usefulness of closures,
just
the difference in behaviour when compared to global variables. Possibly,
with
LISP-like dynamic scoping, a function could access a local variable from
a
calling scope, but to my best knowledge, Ruby is a lexically scoped
language.

David Vallner
430ea1cba106cc65b7687d66e9df4f06?d=identicon&s=25 David Vallner (Guest)
on 2006-08-03 13:44
(Received via mailing list)
I should also really make myself read long blocks of text to avoiding
longer
blocks of text.

DÅ?a Streda 08 Február 2006 05:57 Dave Cantrell napísal:
> In both the Ruby example and the pseudo-code case,
> the variable foo is a globally-scoped variable (well, for that code
> snippet anyway) and therefore should be accessible to any function that
> is subordinate to it.

There's a new term, subordinate functions. But this is essentially the
bit
where you blooped up, foo isn't globally scoped. Not even in that code
snippet. Method definitions aren't a closure on their enclosing lexical
scope
- they run in a separate scope.

>        i = param
>    puts m.run(1)
>

Arguably a better example of shared lexical closure than mine, but I
didn't
feel like hacking up classes. If you can understand why i is four, then
indeed you've pretty much gotten the hang of all there is to it about
how
blocks and closures work.

Hmm, I might even rip off your example as a simple stupefactor for
people that
don't know Ruby to go along with my "open Integer and then define a
linear-time factorial with Enumerable#inject" one.

David Vallner
430ea1cba106cc65b7687d66e9df4f06?d=identicon&s=25 David Vallner (Guest)
on 2006-08-03 14:22
(Received via mailing list)
DÅ?a Å tvrtok 09 Február 2006 02:14 David Vallner napísal:
> I should also really make myself read long blocks of text to avoiding
> longer blocks of text.

And write better English. And spam the list less. The above should read
"to
avoid writing longer blocks of text", in case anyone cares.
D63c268960051bc17a310aa29fffd979?d=identicon&s=25 Dave Cantrell (Guest)
on 2006-08-03 14:22
(Received via mailing list)
David Vallner wrote:
> where you blooped up, foo isn't globally scoped. Not even in that code
> snippet. Method definitions aren't a closure on their enclosing lexical scope
> - they run in a separate scope.

Thanks for taking the time to explain that for me, David.

Yeah, reading back over that I see it sounded kind of weird. I had made
an assumption (I know, I know) that the function declared after the
variable foo was running in the same or subordinate scope as the
variable itself was declared --- whether global or not didn't seem to
matter, but was convenient to write.

So that is definitely where I tripped, because I'm used to dumb
procedural languages (think VBScript and PL/SQL) that work more in that
fashion. I've hacked Python enjoyably, but never fully delved into the
deeper aspects of the language.

Looks like I still have a lot to learn to fully understand Ruby. Luckily
I came to the right place! :)

-dave
This topic is locked and can not be replied to.