Skip to Content
Course content

179: Common Ruby Interview Questions on Blocks vs Procs vs Lambdas Revisited

Click on the "Edit" button in the top corner of the screen to edit your slide content.

Think of these three—blocks, procs, and lambdas—as different levels of commitment when you're asking someone to do a task for you.

A block is like asking a friend who is already standing next to you to hold a bag for a second. They're right there, it's a quick favor, and they aren't a separate "entity" you can hire and move to another room; they're just part of the current conversation.

A Proc is like a freelance contractor. You've signed a contract with them, and you can carry that contract (the object) around and hand it to different managers to execute whenever needed. But Procs are a bit loose; if they decide they are "done" and call a return, they don't just finish their task—they might accidentally walk out of the entire office building (the calling method) and take you with them.

A Lambda is the disciplined professional. Like the Proc, they are a portable object. But they follow the rules strictly. If a lambda returns, it just finishes its own specific task and hands control back to the manager. Plus, if you try to give them three tools when they only asked for two, they'll stop everything and throw a fit (an ArgumentError).

The Return Drama

This is the number one question in Ruby interviews. I've seen people with years of experience stumble here because the behavior feels unintuitive until you see it in action. The difference is all about scope.

def test_proc
  my_proc = Proc.new { return "Proc is leaving the building!" }
  my_proc.call
  "This line will never be reached"
end

def test_lambda
  my_lambda = -> { return "Lambda is just finishing its task" }
  my_lambda.call
  "This line WILL be reached!"
end

puts test_proc   # Output: "Proc is leaving the building!"
puts test_lambda # Output: "This line WILL be reached!"

Notice how the Proc didn't just return a value to the call method; it returned from the test_proc method entirely. The Lambda, however, played nice. It returned from its own block and let the rest of the method finish. If you're writing a piece of logic that needs to be "pluggable" but shouldn't kill your main execution flow, always reach for a lambda.

Why Lambdas are the Strict Siblings

Beyond the return behavior, there's the "Argument Police" aspect. Blocks and Procs are very chill about how many arguments you pass them. If you pass too many, they just ignore the extras. If you pass too few, they treat the missing ones as nil.

Lambdas? Not so much. They insist on an exact match.

my_proc = Proc.new { |a, b| puts "Proc got: #{a}, #{b}" }
my_lambda = ->(a, b) { puts "Lambda got: #{a}, #{b}" }

my_proc.call(1)       # Works! Prints: Proc got: 1, 
my_proc.call(1, 2, 3) # Works! Prints: Proc got: 1, 2 (ignores 3)

my_lambda.call(1)     # ArgumentError: wrong number of arguments (given 1, expected 2)
my_lambda.call(1, 2, 3) # ArgumentError: wrong number of arguments (given 3, expected 2)

I personally prefer lambdas for this reason. When I'm debugging a complex system, I want the code to scream at me if I'm passing the wrong data, rather than silently failing with a bunch of nil values that cause a NoMethodError ten lines later.

When to actually use which

You'll use blocks 90% of the time (think .each or .map) because they're lightweight and don't create an object in memory. But when you find yourself needing to store a piece of logic in a variable, pass it as an argument to another method, or reuse the same logic in multiple places, that's when you move to Procs or Lambdas.

In modern Ruby, the "stabby lambda" syntax (-> { ... }) is the industry standard. You'll rarely see lambda { ... } in professional codebases anymore, but it's good to recognize it in interviews.




📋 Practical Task

Exercise: The Custom Transaction Validator

You are building a payment processing system. You need to create a TransactionProcessor class that can take different "validation rules" as arguments. Some rules should be strict, and some should be flexible.

Your Goal: Implement a system where you can pass a validation rule to a process method.

  • Create a lambda called strict_limit that takes exactly one argument (the amount). It should return true if the amount is less than 100, and false otherwise.
  • Create a proc called loose_limit that takes one argument but doesn't crash if extra metadata is passed to it. It should return true if the amount is less than 500.
  • Write a process(amount, rule) method that calls the rule. If the rule returns false, the method should print "Transaction Rejected". If it returns true, it should print "Transaction Approved".

Test your code with these scenarios:

  1. Call process(50, strict_limit) → Should be Approved.
  2. Call process(150, strict_limit) → Should be Rejected.
  3. Call process(200, loose_limit) → Should be Approved.
  4. Call process(200, loose_limit, "Extra Metadata") → This should not crash (which is why we used a Proc here).
Rating
0 0

There are no comments for now.

to be the first to leave a comment.