3

I am trying some ruby metaprogramming and got some confusion with instance_eval().

see below examples

@instance_var = 'instance_var'
local_var = 'local_var'
obj = Object.new
obj.instance_eval { p @instance_var; p local_var }
obj.instance_eval { @instance_var  = 'instance_var_in_obj'; local_var = 'local_var_in_obj' }
p @instance_var; p local_var

I expect both of @instance_var and local_var can be pass/modify in block but i got

nil
"local_var"
"instance_var"
"local_var_in_obj"

as result we can share(pass/modify) local vars in instance_val but instance vars are belong to self CAN NOT share.

and about instance_exec:

obj.instance_exec(@instance_var) {|instance_var| p instance_var; instance_var = @instance_var }
=> "instance_var"
@instance_var
=> "instance_var"

now i can pass my outer instance var and still CAN NOT modify it.

@instance_arr = []
obj.instance_exec(@instance_arr) {|instance_arr| instance_arr << 'in_block' }
@instance_arr
=> ["in_block"]
obj.instance_exec(@instance_arr) {|instance_arr| instance_arr = [] }
@instance_arr
=> ["in_block"]

with a instance var of array i can modify my instance var but ONLY within current array object

in summary play instance_eval or instance_exec with local vars not instance vars?

is there some concepts i missed?

Arthur H
  • 43
  • 5
  • I can offer 1/2 of an answer. You have two instance variables named @instance_var, one for an instance of `Object` we call `main` and the other `obj`.Within the block of `obj.instance_eval { p @instance_var; p local_var }`, `self` is `obj` and `@instance_var` for that object has not been initialized, so it returns `nil` when referenced. I don't fully understand why the local variable is treated differently, but I suspect it has to do with the fact that referencing an initialized local variable raises an exception. – Cary Swoveland Apr 13 '15 at 07:12
  • thank you for answer, about `@instance_var` the `@` says that you belongs to somebody i think i can understand this part and yes the point of my question is `why the local variable is treated differently` or `local variables` actually belongs to what how to think it in scope?? – Arthur H Apr 13 '15 at 08:40

2 Answers2

1

After some search and advices from my friend i think i figured out the problem. In ruby there is two Context when your code running self and binding, when you work with local vars or method without set self.xxx first thing will be checking is it in your binding object as a local var if not Ruby will think it's a method then search on your self object to find its definition and invoke it. Think this:

class A
  def test
    4
  end
  def use_variable
    test = 5
    test
  end
  def use_method
    test = 5
    self.test
  end
end
a = A.new
a.use_variable # returns 5
a.use_method   # returns 4

That's explained WHY of instance_eval as its document said instance_eval just changed self in the given block and NOT touch binding so methods will be search on new self, local vals still in same binding object.

About instance_exec i'm not very sure about this but seems like instance vars(with at prefix vars) it will be search on self directly skip on binding, so out of instance_exec your @instance_arr belongs to old self and in instance_exec block you got it as a new local var in the new binding of block(block has own scope) but the value of it actually is the reference of @instance_arr so invoke method on the new local var such like push it will change both of them because they share same Array instance, but when you assign a new Array instance to the new local var they are no longer refer same Array instance that's the second WHY.

Arthur H
  • 43
  • 5
0

In order to evaluate the local variable, you would need to pass in the string `"local_var" and it will return the value of the local variable. If you pass in a block, then an argument can not be passed in, according to my interpretation of the documentation.

The behavior of instance eval in the block form is to access as a closure the instance variables and private methods of the object where that call is.

The behavior of instance eval with an argument allows you to evaluate a string in the scope of that call.

vgoff
  • 10,980
  • 3
  • 38
  • 56
  • thank you for answer, your interpretation is right i just missed `binding` concept in mind it can explain the problem. :) – Arthur H Apr 19 '15 at 08:06