The two common ways to call a Ruby block

by Jason Swett,

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 and yield.
  • 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.

Leave a Reply

Your email address will not be published. Required fields are marked *