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" }
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 }
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]
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]
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"
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"]
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" }
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!
Top comments (0)