Why functional patterns complement OOP in Ruby - Performance Analysis
We want to see how combining functional patterns with object-oriented programming affects how long code takes to run.
Specifically, we ask: How does adding functional style change the work done as input grows?
Analyze the time complexity of the following Ruby code mixing OOP and functional style.
class Calculator
def initialize(numbers)
@numbers = numbers
end
def sum_squares
@numbers.map { |n| n * n }.reduce(0, :+)
end
end
calc = Calculator.new([1, 2, 3, 4])
puts calc.sum_squares
This code defines a class holding numbers and uses functional methods to square and sum them.
Look for loops or repeated work inside the code.
- Primary operation: The
mapmethod loops over each number to square it. - Secondary operation: The
reducemethod loops again to add all squared numbers. - How many times: Each method loops once over all numbers, so two passes total.
As the list of numbers grows, the code does more work in two passes.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 20 (10 for map + 10 for reduce) |
| 100 | About 200 (100 + 100) |
| 1000 | About 2000 (1000 + 1000) |
Pattern observation: The work grows roughly twice as fast as the input size because of two passes.
Time Complexity: O(n)
This means the time to finish grows directly in proportion to how many numbers we have.
[X] Wrong: "Using two loops means the time complexity is squared, like O(n²)."
[OK] Correct: The loops run one after another, not inside each other, so their times add up, not multiply.
Understanding how functional methods work inside classes helps you explain clear, readable code that scales well.
What if we combined the map and reduce into a single loop? How would the time complexity change?
Practice
Solution
Step 1: Understand functional patterns in Ruby
Functional patterns emphasize small, reusable methods that avoid changing data outside their scope (no side effects).Step 2: Understand OOP's role
OOP organizes code around objects that combine data and behavior, making programs easier to manage.Final Answer:
Functional patterns create small, reusable methods without side effects, improving code clarity. -> Option DQuick Check:
Functional patterns improve clarity by avoiding side effects [OK]
- Thinking functional replaces OOP completely
- Believing OOP ignores methods
- Assuming functional always makes code faster
Solution
Step 1: Identify pure function characteristics
A pure function returns a value based only on input and does not change external variables or produce side effects.Step 2: Check each option
def double(x); x * 2; end returns x * 2 without changing anything else. def double(x); @value = x * 2; end changes an instance variable (@value), so it has side effects. def double(x); puts x * 2; end prints output (side effect). def double(x); x *= 2; nil; end modifies x locally but returns nil, so it doesn't return the doubled value.Final Answer:
def double(x); x * 2; end -> Option AQuick Check:
Pure function returns value only [OK]
- Using instance variables inside pure functions
- Printing inside functions instead of returning
- Not returning the computed value explicitly
class Calculator
def initialize(value)
@value = value
end
def double
@value * 2
end
def apply(func)
func.call(@value)
end
end
calc = Calculator.new(5)
puts calc.double
puts calc.apply(->(x) { x + 3 })Solution
Step 1: Understand the Calculator class methods
The double method returns @value * 2, so for 5 it returns 10. The apply method calls the passed function with @value.Step 2: Evaluate the output of puts statements
calc.double prints 10. calc.apply calls the lambda adding 3 to 5, so prints 8.Final Answer:
10 8 -> Option AQuick Check:
double = 10, apply adds 3 = 8 [OK]
- Confusing lambda call syntax
- Expecting apply to modify @value
- Mixing up output values
class Counter
def initialize
@count = 0
end
def increment
@count += 1
end
def apply(func)
func(@count)
end
end
counter = Counter.new
counter.increment
puts counter.apply(->(x) { x * 2 })Solution
Step 1: Check how func is used in apply method
In Ruby, to call a lambda or Proc, you must use .call, not func().Step 2: Identify the error
func(@count) will cause a NoMethodError because func is a Proc object and needs .call.Final Answer:
func should be called with .call, not func() -> Option CQuick Check:
Call lambdas with .call [OK]
- Calling lambda like a normal method
- Forgetting to initialize instance variables
- Incorrect lambda syntax
Solution
Step 1: Understand the requirement
The method should not change the original list but return a new list with doubled values.Step 2: Evaluate options for functional and OOP style
Usingmapreturns a new array without side effects, fitting functional style. Modifying original data or using global variables breaks this principle.Final Answer:
Define a method that returns a new array usingmapwithout modifying the original list. -> Option BQuick Check:
Use map for new array, avoid side effects [OK]
- Modifying original array instead of returning new
- Using global variables for data storage
- Storing results in instance variables unnecessarily
Ready to prove it?
Pass the test and this pattern moves unknown
