Blocks, Procs, and Lambdas for functional programming

Sarah Mitchell Feb 2026
3 tabs
class Timer
  def self.measure
    start_time = Time.now
    yield if block_given?
    end_time = Time.now
    end_time - start_time
  end
end

# Usage:
duration = Timer.measure do
  sleep(1)
  puts "Heavy operation"
end
# => 1.002 (seconds)

# Blocks with parameters
class Array
  def my_each
    return enum_for(:my_each) unless block_given?

    i = 0
    while i < length
      yield self[i]
      i += 1
    end
    self
  end

  def my_map
    return enum_for(:my_map) unless block_given?

    result = []
    my_each { |item| result << yield(item) }
    result
  end
end

[1, 2, 3].my_map { |n| n * 2 }  # => [2, 4, 6]
3 files · ruby Explain with highlit

Ruby's closures—blocks, procs, lambdas—enable functional programming patterns. Blocks are anonymous code chunks passed to methods. Procs are objects wrapping blocks, callable with call. Lambdas are stricter procs—check argument count and return differently. I use yield for simple block invocation, block_given? to check presence. &block converts blocks to procs. Lambdas with -> syntax are concise. Closures capture surrounding scope, enabling powerful abstractions. Return behavior differs—lambdas return to caller, procs return from enclosing method. I prefer lambdas for predictable behavior. Understanding closures unlocks Ruby's expressiveness—iterator methods, callbacks, DSLs. They're fundamental to idiomatic Ruby code.