Ruby blocks can be difficult to understand. One of the details which presents an obstacle to fully understanding blocks is the fact that there is more than one way to call a block.
In this post we’ll go over the two most common ways of calling a Ruby block: block.call
and yield
.
There are also other ways to call a block, e.g. instance_exec
. But that’s an “advanced” topic which I’ll leave out of the scope of this post.
Here are the two common ways of calling a Ruby block and why they exist.
The first way: block.call
Below is a method that accepts a block, then calls that block.
def hello(&block)
block.call
end
hello { puts "hey!" }
If you run this code, you’ll see the output hey!
.
You may wonder what the &
in front of &block
is all about. As I explained in a different post, the &
converts the block into a Proc object. The block can’t be called directly using .call
. The block has to be converted into a Proc
object first and then .call
is called on the Proc
object.
I encourage you to read my two other posts about Proc objects and the & at the beginning of &block if you’d like to understand these parts more deeply.
The second way: yield
The example below is very similar to the first example, except instead of using block.call
we’re using yield
.
def hello(&block)
yield
end
hello { puts "hey!" }
You may wonder: if we already have block.call
, why does Ruby provide a second, slightly different way of calling a block?
One reason is that yield
gives us a capability that block.call
doesn’t have. In the below example, we define a method and then pass a block to it, but we never have to explicitly specify that the method takes a block.
def hello
yield
end
hello { puts "hey!" }
As you can see, yield
gives us the ability to call a block even if our method doesn’t explicitly take a block. (Side note: any Ruby method can be passed a block, even if the method doesn’t explicitly take one.)
The fact that yield
exists raises the question: why not just use yield
all the time?
The answer is that when you use block.call
, you have the ability to pass the block to another method if you so choose, which is something you can’t do with yield
.
When we put &block
in a method’s signature, we can do more with the block than just call it using block.call
. We could also, for example, choose not to call the block but rather pass the block to a different method which then calls the block.
Takeaways
- There are two common ways to call a Ruby block:
block.call
andyield
. - Unlike
block.call
,yield
gives us the ability to call a block even if our method doesn’t explicitly take a block. - Unlike using an implicit block and
yield
, using and explicit block allows us to pass a block to another method.
Thank you.
is it possible to use the yield keyword with an explicit block?