Define_method with closures in Ruby - Time & Space Complexity
We want to understand how the time it takes to create methods using define_method with closures changes as we add more methods.
How does the number of methods affect the work done when defining them?
Analyze the time complexity of the following code snippet.
class Greeter
def initialize(names)
names.each do |name|
self.class.define_method("greet_#{name}") do
"Hello, #{name}!"
end
end
end
end
Greeter.new(["alice", "bob", "carol"])
This code creates a new method for each name in the list, using closures to remember each name.
- Primary operation: Looping over the list of names to define methods.
- How many times: Once for each name in the input list.
Each new name adds one more method definition, so the work grows directly with the number of names.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | 10 method definitions |
| 100 | 100 method definitions |
| 1000 | 1000 method definitions |
Pattern observation: The work grows in a straight line as the input size increases.
Time Complexity: O(n)
This means the time to define methods grows directly in proportion to the number of names.
[X] Wrong: "Defining methods with closures happens instantly, no matter how many methods we add."
[OK] Correct: Each method definition takes some time, so more methods mean more work overall.
Understanding how loops and method definitions scale helps you explain how your code behaves with bigger inputs, a skill useful in many programming tasks.
What if we changed the code to define methods inside a nested loop? How would the time complexity change?
Practice
define_method do in Ruby?Solution
Step 1: Understand the purpose of
define_methoddefine_methodis used to create methods dynamically at runtime using a block of code.Step 2: Compare with other options
Options B, C, and D describe different actions unrelated todefine_method.Final Answer:
Creates a method dynamically using a block -> Option DQuick Check:
define_methodcreates methods dynamically [OK]
- Thinking define_method calls methods
- Confusing define_method with deleting methods
- Assuming it defines variables
greet using define_method that returns "Hello"?Solution
Step 1: Recall correct
The correct syntax uses a symbol for the method name and a block:define_methodsyntaxdefine_method(:name) { ... }.Step 2: Check each option
def define_method(:greet) "Hello" end usesdefincorrectly. define_method greet { return "Hello" } lacks symbol (greetundefined). define_method(:greet, "Hello") passes string instead of block. B matches correct syntax.Final Answer:
define_method(:greet) { "Hello" } -> Option CQuick Check:
Correct syntax uses symbol and block [OK]
- Using method name without symbol
- Incorrect block syntax
- Using def inside define_method
class Person
def initialize(name)
@name = name
self.class.define_method(:greet) { "Hello, #{@name}!" }
end
end
p = Person.new("Alice")
puts p.greetSolution
Step 1: Understand closure and instance variable scope
The block passed todefine_methoddefines the method body. However, the string interpolation"Hello, #{@name}!"is evaluated immediately whendefine_methodis called, not when the method is invoked. At that time,@nameis nil because the block is defined in the class context, not the instance context.Step 2: Predict output
Therefore, the methodgreetreturns the string with@nameinterpolated as nil, resulting in "Hello, !".Final Answer:
Hello, ! -> Option BQuick Check:
String interpolation in define_method block evaluated immediately [OK]
- Thinking @name is dynamically resolved inside the block
- Expecting 'Hello, Alice!' due to misunderstanding of closure
- Confusing instance and class scope
class Calculator
def initialize(x)
@x = x
self.class.define_method(:square) { @x * @x }
end
end
calc = Calculator.new(4)
puts calc.squareSolution
Step 1: Analyze where define_method is called
define_methodonself.classdefines an instance methodsquare. The block executes in instance context.Step 2: Understand closure and instance variable scope
@xresolved on instance:4 * 4 = 16. No capture issue, no error.Final Answer:
No error, outputs 16 -> Option AQuick Check:
Instance vars work in class-level define_method [OK]
- Thinking method undefined for instances
- Expecting syntax error
- Believing nil * nil error from poor capture
Person has a greet method that correctly uses its own @name?
class Person
def initialize(name)
@name = name
self.class.define_method(:greet) { "Hello, #{@name}!" }
end
end
p1 = Person.new("Bob")
p2 = Person.new("Carol")
puts p1.greet
puts p2.greetSolution
Step 1: Understand the problem with class-level define_method
Class-leveldefine_methodininitializeredefines a shared instance method each time (inefficient, problematic for local var closures). Instance vars work via dynamic lookup.Step 2: Use define_singleton_method to define method per instance
define_singleton_methoddefines on the instance's singleton class, giving each its owngreetaccessing own@name.Final Answer:
Define greet method inside initialize usingdefine_singleton_method-> Option AQuick Check:
Use define_singleton_method for per-instance closures [OK]
- Trying to pass instance vars as parameters to class method
- Using class variables instead of instance variables
- Defining method with def inside initialize incorrectly
Ready to prove it?
Pass the test and this pattern moves unknown
