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.

ruby
# 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

ruby
p = Proc.new { |a, b| [a, b] }
p.call(1)           # [1, nil]   — missing args become nil

l = ->(a, b) { [a, b] }
l.call(1)           # ArgumentError

Lambdas behave like methods. Procs are forgiving, which is occasionally useful and usually a bug waiting to happen.

#Difference 2: what return does

ruby
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
end

This is why lambdas are the safer default when storing a callback.

#Accepting a block in your own method

ruby
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 &:

ruby
def run(&block)
  block.call
end

That & is also what makes map(&:upcase) work — it converts the symbol to a proc.