Blocks, procs and lambdas in Ruby
Short answer
A block is passed to a method with do...end or {}. A proc and a lambda are blocks stored in variables — and lambdas check argument count and return only from themselves.
# Block — not an object, tied to a method call
[1, 2, 3].each { |n| puts n }
# Proc — an object
double = Proc.new { |n| n * 2 }
double.call(5) # 10
# Lambda — also a Proc object, with stricter rules
triple = ->(n) { n * 3 }
triple.call(5) # 15#Difference 1: argument checking
p = Proc.new { |a, b| [a, b] }
p.call(1) # [1, nil] — missing args become nil
l = ->(a, b) { [a, b] }
l.call(1) # ArgumentErrorLambdas behave like methods. Procs are forgiving, which is occasionally useful and usually a bug waiting to happen.
#Difference 2: what return does
def with_lambda
l = -> { return 10 }
l.call
20 # returns 20 — the lambda returned from itself
end
def with_proc
p = Proc.new { return 10 }
p.call
20 # never reached — returns 10 from the whole method
endThis is why lambdas are the safer default when storing a callback.
#Accepting a block in your own method
def twice
yield
yield
end
twice { puts "hello" }yield calls whatever block was passed. block_given? checks whether there was one.
To capture it as an object, prefix a parameter with &:
def run(&block)
block.call
endThat & is also what makes map(&:upcase) work — it converts the symbol to a proc.