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?

2
  • 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. Commented Apr 13, 2015 at 7: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?? Commented Apr 13, 2015 at 8:40

2 Answers 2

2

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.

Sign up to request clarification or add additional context in comments.

Comments

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.

1 Comment

thank you for answer, your interpretation is right i just missed binding concept in mind it can explain the problem. :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.