DEV Community

Cover image for Ruby Basics: Blocks, Procs, and Lambdas
Jessie Rohrer
Jessie Rohrer

Posted on

Ruby Basics: Blocks, Procs, and Lambdas

Photo by Tania Malréchauffé on Unsplash


What is a Block?

A block is a bit of code that can be executed. They are contained between do and end keywords or inside of curly braces. Blocks can be combined with methods like Ruby iterators to execute an instruction for each element in a collection (like an array or a hash). Many Ruby methods accept blocks.

5.times do
    puts "Hello World"
end

5.times { puts "Hello World" }
Enter fullscreen mode Exit fullscreen mode

Let's review: Return Values for Common Ruby Iterators

  • .each -- returns the original array
  • .map or .collect -- return a new array
  • .select -- returns a new array
  • .find -- returns an element from the original array

What Is a Proc?

Blocks are one of the few things in Ruby that are not objects. Because they aren't object, blocks can't be saved to variables and don't have the same abilities as a real object. To give a block the functionality of a Ruby object, we need to use procs. Think of a proc as a saved block. Just like you can give some code a name and turn it into a method, you can give a block a name and turn it into a proc.
Why should we use procs? They help keep our code DRY. If you find yourself using the same block over and over, you can turn it into a proc (similar to creating helper methods). Also, procs are full-fledged Ruby objects with all the functionality that entails.
Procs can be defined by calling Proc.new and passing in the block of code you want to save.

square = Proc.new { |x| x ** 2 }
Enter fullscreen mode Exit fullscreen mode

This is a proc that squares a number. We can now pass this proc to a method that would otherwise take a block, and we don't have to re-write the code to square the numbers in a collection.

[2,4,6].collect!(&square)
#==> [4, 16, 36]

[1,3,5].map!(&square)
#==> [1, 9, 25]
Enter fullscreen mode Exit fullscreen mode

Which is the same as:

[2,4,6].collect!{ |x| x ** 2 }
#==> [4, 16, 36]

[1,3,5].map!{ |x| x ** 2 }
#==> [1, 9, 25]
Enter fullscreen mode Exit fullscreen mode

Reminder: Collect and Map do the same thing. The bang next to the method forces the array to change from the original values to the new ones. The original array is replaced by the new one. The "&" is used to convert the proc into a block.

We can also call procs directly with Ruby's call method:

greeting = Proc.new { puts "Hello" }
greeting.call 
#==> "Hello"
Enter fullscreen mode Exit fullscreen mode

And we can convert symbols to procs with the "&" syntax:

numbers = [1, 2, 3, 4, 5, 6, 7, 8]
strings = numbers.map(&:to_s)
puts strings
# ==> ["1", "2", "3", "4", "5", "6", "7", "8"]
Enter fullscreen mode Exit fullscreen mode

By mapping &:to_s over every element in the numbers array, we turned each integer into a string.

What is a Lambda

Like procs, lambdas are Ruby objects. They are similar with the exception of syntax and some behavioral changes.

Lambda syntax:
lambda { |param| block }

lambda { puts "hello" } 
is like calling 
Proc.new { puts "hello" }
Enter fullscreen mode Exit fullscreen mode

Lambdas are useful in the same situations as procs, but there are a couple of major differences between the two. The first is that a lambda checks the number of arguments passed to it, while a proc does not. The lambda will throw an error if you pass the wrong number of arguments to it, but a proc will ignore unexpected arguments and assign nil to any arguments that are missing.
The second is that when a lambda returns, it passes control back to the calling method. When a proc returns, it does so immediately, without going back to the method that called it.

For example:

def rock_vs_paper_proc
    winner = Proc.new { return "Rock wins!" }
    winner.call
    "Paper wins!"
end

puts rock_vs_paper_proc

def rock_vs_paper_lambda
    winner = lambda { return "Rock wins!" }
    winner.call
    "Paper wins!"
end

puts rock_vs_paper_lambda

# ==> Rock wins!
# ==> Paper wins!
Enter fullscreen mode Exit fullscreen mode

Top comments (0)