Blocks, Procs, and Lambdas

You have already been using blocks without knowing the name. 5.times { |i| puts i } and cart.each do |item| …​ end both hand a chunk of code to a method — that chunk is a block. Once you see blocks as first-class pieces of code, several other Ruby features fall into place.

Blocks

The two block forms are interchangeable. Convention: { } for one-liners, do …​ end for multi-line blocks.

$ irb
>> [1, 2, 3].each { |n| puts n * 2 }
2
4
6
=> [1, 2, 3]
>> [1, 2, 3].each do |n|
?>   doubled = n * 2
>>   puts doubled
>> end
2
4
6
=> [1, 2, 3]
>> exit

Writing a Method That Takes a Block

Inside a method, yield runs the block that was passed in:

twice.rb
def twice
  yield
  yield
end
$ irb
>> load './twice.rb'
=> true
>> twice { puts 'hello' }
hello
hello
=> nil
>> exit

You can also pass values to the block:

each_name.rb
def each_name
  yield 'Alice'
  yield 'Bob'
  yield 'Carol'
end
$ irb
>> load './each_name.rb'
=> true
>> each_name { |name| puts "Hi #{name}" }
Hi Alice
Hi Bob
Hi Carol
=> nil
>> exit

This is exactly how Array#each is built internally.

Procs

A Proc is a block stored in a variable. You build one with Proc.new or the shorthand proc, and call it with .call:

$ irb
>> greet = Proc.new { |name| puts "Hello #{name}" }
=> #<Proc:...>
>> greet.call('Stefan')
Hello Stefan
=> nil
>> exit

Procs are useful when you want to reuse the same block or pass it around like any other value.

Lambdas

A lambda is a stricter Proc. Create one with the arrow syntax:

$ irb
>> square = ->(n) { n * n }
=> #<Proc (lambda)>
>> square.call(5)
=> 25
>> square.(5)
=> 25
>> square[5]
=> 25
>> exit

The three call styles are equivalent. The arrow syntax is the modern Ruby idiom.

The practical difference from a Proc is that a lambda checks the number of arguments (too many or too few raises an error) and a bare return inside a lambda returns from the lambda, not from the surrounding method. In day-to-day beginner code you will rarely notice. Reach for lambdas when you want the stricter behavior, and for blocks when you just need a piece of code to hand to a method.