Class_eval and instance_eval in Ruby - Time & Space Complexity
When using class_eval and instance_eval, it's important to understand how the time to run these methods grows as the code inside them gets bigger.
We want to know how the number of operations changes when we evaluate code blocks on classes or objects.
Analyze the time complexity of the following code snippet.
class MyClass
def self.add_methods(n)
n.times do |i|
class_eval do
define_method("method_#{i}") { i }
end
end
end
end
MyClass.add_methods(5)
This code adds n methods to a class using class_eval inside a loop.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: The loop that runs
ntimes, each time callingclass_evalto define a method. - How many times: Exactly
ntimes, once per method added.
Each time we increase n, the number of method definitions grows linearly.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | 10 method definitions |
| 100 | 100 method definitions |
| 1000 | 1000 method definitions |
Pattern observation: The work grows directly with n. Doubling n doubles the work.
Time Complexity: O(n)
This means the time to run grows in a straight line with the number of methods you add.
[X] Wrong: "Using class_eval or instance_eval runs instantly no matter how many times."
[OK] Correct: Each time you evaluate code, Ruby runs that code, so more code means more time. The cost adds up with each method defined.
Understanding how dynamic code evaluation scales helps you write efficient Ruby code and explain your reasoning clearly in interviews.
"What if we replaced class_eval with a single class_eval block that defines all methods inside it? How would the time complexity change?"
Practice
class_eval and instance_eval in Ruby?Solution
Step 1: Understand
class_evalbehaviorclass_evalopens the class and changes it, so all instances see the change.Step 2: Understand
instance_evalbehaviorinstance_evalruns code in the context of a single object, changing only that object.Final Answer:
class_evalchanges the class and affects all instances;instance_evalchanges only one object. -> Option CQuick Check:
class_eval = class-wide, instance_eval = single object [OK]
- Confusing which method affects the class vs. single object
- Thinking both methods change the whole class
- Assuming instance_eval changes all instances
greet to class Person using class_eval?Solution
Step 1: Recall correct block syntax for class_eval
class_evaltakes a block with method definitions inside curly braces or do-end.Step 2: Check method definition placement
Methodgreetmust be defined inside the block passed toclass_eval.Final Answer:
Person.class_eval { def greet; 'Hi'; end } -> Option AQuick Check:
class_eval uses block with method defs [OK]
- Omitting braces or block for class_eval
- Using instance_eval instead of class_eval for class methods
- Writing method defs outside the block
class Dog
def initialize(name)
@name = name
end
end
fido = Dog.new('Fido')
fido.instance_eval { def speak; "Woof! I'm #{@name}"; end }
puts fido.speak
rex = Dog.new('Rex')
puts rex.respond_to?(:speak)Solution
Step 1: Understand instance_eval adds method to one object
Thespeakmethod is added only tofido, not to other Dog instances.Step 2: Check outputs
fido.speakprints "Woof! I'm Fido".rex.respond_to?(:speak)returns false becauserexhas nospeakmethod.Final Answer:
Woof! I'm Fido false -> Option AQuick Check:
instance_eval adds method to one object only [OK]
- Assuming all instances get the new method
- Expecting true for rex.respond_to?(:speak)
- Confusing instance_eval with class_eval
class Cat
end
kitty = Cat.new
kitty.class_eval { def meow; 'Meow!'; end }
puts kitty.meowSolution
Step 1: Check receiver of class_eval
class_evalis a method of Class, not of instances; calling it on an instance raises NoMethodError.Step 2: Verify execution
Sincekittyis an instance,kitty.class_evalraises NoMethodError; thus,puts kitty.meowis not reached.Final Answer:
NoMethodError because class_eval is called on instance -> Option BQuick Check:
class_eval is a Class method, not instance method [OK]
- Thinking class_eval can be called on instances
- Expecting NoMethodError for instance.class_eval
- Confusing class_eval usage with class-only restriction
class Car
def initialize(model)
@model = model
end
end
car1 = Car.new('Toyota')
car2 = Car.new('Honda')
Car.class_eval do
def info
"Model: #{@model}"
end
end
car1.instance_eval do
def info
"Special Model: #{@model.upcase}"
end
end
puts car1.info
puts car2.infoSolution
Step 1: Understand class_eval adds method to all instances
infomethod added byclass_evalreturns "Model: #{@model}" for all cars.Step 2: Understand instance_eval overrides method for one object
car1.instance_evalredefinesinfoonly forcar1, returning uppercase model with "Special Model:" prefix.Step 3: Check outputs
car1.infoprints "Special Model: TOYOTA";car2.infoprints "Model: Honda".Final Answer:
Special Model: TOYOTA Model: Honda -> Option DQuick Check:
class_eval affects all; instance_eval overrides one [OK]
- Assuming instance_eval changes all instances
- Expecting both outputs to be 'Special Model'
- Confusing which method is called on which object
Ready to prove it?
Pass the test and this pattern moves unknown
