instance_eval moves self, class_eval moves def¶
Level: 301 · for a reader who has seen Klass.class_eval { def ... } in a library and obj.instance_eval { @x } in a test and wants to know which one to write
One line: Both evals run a block with self set to the receiver; the difference is where a def inside lands — class_eval on a class defines instance methods, instance_eval on anything defines singleton methods of that thing — and Python, which has no way to change what self means, does the same jobs with exec, setattr, classmethod and types.MethodType.
A Ruby block remembers the self of the place it was written. instance_eval and class_eval are the two methods that override that memory and run the block with a different self: obj.instance_eval { @secret } reads an instance variable from outside, Klass.class_eval { ... } reopens a class you hold in a variable. What separates them is a second, quieter setting — the default definee, the class that a bare def inside the block adds a method to. class_eval (alias module_eval) sets both self and the definee to the class, so def makes an instance method. instance_eval sets self to the receiver and the definee to the receiver's singleton class, so def makes a method of that one object — and when the receiver is a class, "that one object" is the class, which is why Klass.instance_eval { def y } defines a class method. Both also take a string instead of a block; a string is compiled at run time and needs __FILE__ and __LINE__ to give errors a place to point at. instance_exec is instance_eval with arguments. The program measures each of these, then two things people trip over: what a block or a string can see, and why class klass is not a way to reopen a class held in a variable.
Verified output of instance_eval_and_class_eval_rb.rb — regenerated by tools/run_examples.py, never hand-typed.
1. safe.instance_eval { @secret } 42
2. safe.instance_eval { self.class } Safe
3. Safe.class_eval { def x }: Safe.new.x "instance x"
Safe.x NoMethodError: undefined method 'x' for class Safe
4. Safe.instance_eval { def y }: Safe.y "class y"
Safe.new.y NoMethodError: undefined method 'y' for an instance of Safe
5. safe.instance_eval { def only_me } safe.singleton_methods = [:only_me]
Safe.new.respond_to?(:only_me) false
6. safe.instance_exec(3) { |n| @secret + n } 45
instance_eval { |o| o.equal?(safe) } true
instance_eval(&-> { 1 }) -- a strict lambda ArgumentError: wrong number of arguments (given 1, expected 0)
7. class_eval("def z = 3", __FILE__, __LINE__ + 1) source_location = instance_eval_and_class_eval_rb.rb:48
class_eval("def w = 4") -- no file, no line source_location = (eval at instance_eval_and_class_eval_rb.rb:49):1
8. class_eval { factor * 2 } -- a block closes 6
9. class_eval { 1 + 1 } / instance_eval("1 + 1") 2 / 2
10. blk = proc { self.class }; blk.call Object
safe.instance_eval(&blk) Safe
11. class klass; end -- a variable, not a constant SyntaxError
klass.class_eval { def v = 5 }: klass.new.v 5
12. x = 5; eval("x + 1") -- the current scope 6
13. module_eval == class_eval (same method) true
Reading the output¶
Rows 1 and 2: inside instance_eval the block's self is safe, so @secret is safe's variable and self.class is Safe. Rows 3 and 4 are the classic pair: class_eval { def x } gives every Safe an x and the class itself has none; instance_eval { def y } gives the class Safe a y and instances have none. Row 5 is the same rule on a plain object — the def landed on safe's singleton class, so safe.singleton_methods lists it and a second Safe does not respond. Row 6: instance_exec passes arguments; instance_eval passes exactly one, the receiver itself, which is why the block form { |o| ... } sees safe and why a zero-argument lambda — strict about its count — raises ArgumentError when handed to it. Row 7 is the string form: with __FILE__ and __LINE__ + 1 the method's source_location is this file and the line after the call; without them it is (eval at ...), line 1, which is what a backtrace will show you at three in the morning. Row 8: a block is a closure and sees factor; a string is compiled fresh in the class's scope and does not. Row 9: both evals return the block's or string's last value. Row 10: a proc called normally keeps its birthplace self (Object, the top-level object's class); instance_eval moves it. Row 11 is why class_eval exists at all: class needs a constant, so class klass is a SyntaxError, while klass.class_eval { def v } reopens whatever class the variable holds. Row 12: plain eval sees the current scope. Row 13: module_eval and class_eval are literally the same method.
Compared with Python¶
Python has no mechanism for changing what self means, because self is not a keyword: it is the first parameter of a function, and it is whatever you pass (row 2, row 10). So every row has a twin, but none of them switches anything. Reading a private variable is vars(safe)["_secret"] or simply safe._secret (row 1). The two def destinations of rows 3 and 4 become two explicit choices: exec a def into a namespace dictionary and setattr the function onto the class for an instance method, or wrap it in classmethod for a class method — with one asymmetry: a Python class method is reachable through an instance as well, while Ruby's Safe.new.y fails. Row 5, a method for one object, is types.MethodType(func, obj) stored on that object. Row 6: arguments need no instance_exec — they are parameters — and there is no strict/lenient split to trip on. Row 7: compile(src, "generated.py", "exec") gives generated code a filename for tracebacks, the same job as __FILE__/__LINE__; a bare exec(src) reports <string>. Row 8: eval sees the current scope by default and an explicit {} takes it away — the mirror of Ruby's block-versus-string split. Row 9 is the other structural fact: eval returns an expression's value, exec runs statements and returns None; Ruby's evals do both jobs and return the last value. Row 11 has a Python surprise of its own: class klass: is not an error — it creates a new class and binds the name klass to it, so the variable no longer refers to Safe. Row 13: eval and exec are two builtins, where module_eval and class_eval are one method under two names.
Verified output of instance_eval_and_class_eval_py.py — regenerated by tools/run_examples.py, never hand-typed.
1. vars(safe)["_secret"] -- nothing to switch 42
2. peek(safe) -- self is the argument Safe
3. exec("def x(self) ...") + setattr: Safe().x() 'instance x'
Safe.x() -- no instance to be self TypeError
4. Safe.y = classmethod(...): Safe.y() 'class y'
Safe().y() -- reachable from instances too 'class y'
5. safe.only_me = MethodType(f, safe) in vars(safe): ['only_me']
hasattr(Safe(), "only_me") False
6. add(safe, 3) -- self and args are parameters 45
types.MethodType(add, safe)(3) 45
no strict/lenient split a function takes exactly its parameters
7. compile(src, "generated.py", "exec") co_filename = generated.py:1
exec(src) -- no filename co_filename = <string>
8. eval("factor * 2") -- sees the current scope 6
eval("factor * 2", {}) -- an empty namespace NameError
9. eval("1 + 1") / exec("1 + 1") 2 / None
10. peek(A()) / peek(safe) -- self is passed in A / Safe
a function has no self to move -
11. setattr(klass, 'v', ...): klass().v() 5
class klass: pass -> klass is Safe False
12. x = 5; eval("x + 1") -- the current scope 6
13. eval is exec -- two builtins, not aliases False
The rule that -c runs a script and only the prompt shows an expression's value is the same expression/statement split as row 9: -c is not the prompt ↗ in the Python library.
Try it¶
- Give one
Personagreetmethod withinstance_evaland everyPersonawavemethod withclass_eval; useinstance_execto pass a suffix into a block that changes the person's@name. Printsingleton_methodsof the one,instance_methods(false)of the class, andrespond_to?(:greet)from a second person. - Write
Module#def_from_string(name, body)that usesclass_evalwith a string and passes__FILE__and__LINE__; define two methods with it and printinstance_method(:name).source_locationfor each — then remove the file and line arguments and print again. Which one would you rather see in a backtrace?
Solution to 1
instance_eval_and_class_eval_kata_rb.rb in full — pasted here by tools/run_examples.py from the file CI runs.
# instance_eval_and_class_eval_kata_rb.rb — one method for one person, one for all of them.
class Person
def initialize(name) = @name = name
end
ada = Person.new("Ada")
bob = Person.new("Bob")
ada.instance_eval do # self is ada; def lands on ada's singleton class
def greet = "Hello from #{@name}"
end
Person.class_eval do # self is Person; def lands on Person
def wave = "#{@name} waves"
end
suffix = "!"
ada.instance_exec(suffix) { |s| @name += s } # arguments come through instance_exec
puts "1. ada.greet -> #{ada.greet.inspect}"
puts "2. bob.respond_to?(:greet) -> #{bob.respond_to?(:greet)}"
puts "3. ada.singleton_methods -> #{ada.singleton_methods.inspect}"
puts "4. bob.wave -> #{bob.wave.inspect}"
puts "5. Person.instance_methods(false) -> #{Person.instance_methods(false).sort.inspect}"
puts "6. ada.instance_variable_get(:@name) -> #{ada.instance_variable_get(:@name).inspect}"
Verified output of instance_eval_and_class_eval_kata_rb.rb — regenerated by tools/run_examples.py, never hand-typed.
See also¶
- A DSL is
instance_evalplus stored blocks — the main reason to moveself define_methodturns a block into a method — the block-based alternative toclass_evalwith a stringClass.newmakes a class; a constant names it —Class.new { ... }runs its block withclass_eval- Singleton classes — the class that
instance_eval'sdeflands on Bindingandeval—evalwith an explicitBinding, and Python'seval(expr, globals, locals)selfis implicit — whatselfis before anything moves it-cis not the prompt ↗ — the Python library on expressions that have a value and statements that do not