From: Brian Candler Date: 2010-10-04T18:44:24+09:00 Subject: Re: Pass by reference and copy on write Ralph Shnelvar wrote: > BC> (*) Unless you pass a Binding object explicitly, in which case it is > BC> possible to eval code which affects local variables in other scopes. > > Could I ask you to explain this REALLY SLOWLY so that people like me can > understand this ... PLEASE. A bit of code will speak louder than words. def increment_a(b) eval "a += 1", b end a = 123 increment_a(binding) puts a # prints 124 What's going on? Well, you probably know that a method (def .. end) starts a new local variable scope, so normally inside method increment_a you would not have access to any local variables defined outside. The method Kernel#binding returns an instance of a Binding object, which gives you access to the current local variable scope. We pass that Binding object as a parameter to increment_a, which can then eval some code in that scope. What Binding gives you is access to the "activation record" - the place where local variables are stored. In C this would be called the "stack frame", but in Ruby it's more like a heap than a stack, since bits of it can persist after the method returns. Creating an explicit Binding object is one way to make the activation record persist and/or pass it around for remote access. You also get an implicit Binding whenever you pass a block: def inc_a(&blk) yield eval "a += 1", blk.binding end a = 123 inc_a { puts "Hello" } puts a Another way to persist an activation record is to create a "closure". Normally, when a method returns, its activation record is garbage-collected, because all its local variables drop out of scope. However, if you create an anonymous function which uses that activation record, it will persist as long as that function persists. def make_a_counter a = 0 lambda { a += 1 } end c1 = make_a_counter c2 = make_a_counter puts c1.call # 1 puts c1.call # 2 puts c2.call # 1 puts c2.call # 2 Each time you call make_a_counter it creates its own local variable scope, in which 'a' is defined. Then it returns a function which increments that particular instance of 'a'. So c1 and c2 are lambdas which increment different instances of 'a'. They both carry state. You can even bootstrap objects this way. Closures are a standard concept in many high-level languages, and you can google for more info. The point is: in Ruby, none of these mechanisms lets me obtain a pointer or reference to the particular slot in the activation record which holds the current value of variable 'a'. Therefore there is no "pass by reference" of the kind you originally referred to. But I *can* get a handle to the entire activation record, and then eval code which manipulates 'a' directly. Regards, Brian. -- Posted via http://www.ruby-forum.com/.