Programming ≈ Fun

Written by Krešimir Bojčić

What the Heck Are Closures in Ruby?

What exactly is closure? It’s a convenient way of passing variables that you might need inside your block. But how does the block know which ones you’ll need? Well it doesn’t so it copies every single one of them. Only condition is they have to come in scope before the beginning of the block. Thats what I’ll be calling “scope” from now on.

Every variable that is in “scope” is copied and “combined” with the block. That way you can access them inside the block. Otherwise it would be cumbersome to add all those arguments that you need.

You can visualize it as if the block is dragging along all the buddies that he just met. Rule of thumb is that you are sending as an argument only variables that are needed for a method using block, not the block itself.

Let’s clarify this with an example (I’ll use explicit blocks because I think implicit blocks are evil, especially when trying to figure them out):

#passing the description to the block
def change_customer_name(id, full_name)
  with_logging('change_customer_name') do
   customer = Customer.find(id);
   customer.full_name = full_name

def change_customer_age(id, age)
  with_logging('change_customer_age') do
   customer = Customer.find(id);
   customer.age = age

def with_logging( description, &the_block )
  begin"Starting request #{description}") # do the actual thing"Completed request #{description}")
    @logger.error("Request failed, it's all your fault!")

As you can see we have id and the customer name and age available in the block by convention. That is closure. Only argument that we are sending is a description that is needed for the method containing block, not the block itself.

Things to keep in mind:

  • Block saves a copy of variables in “scope”, so if you change them, original values are not changed
  • Watch out for the size of variables in “scope”. If you save block for later use, remember that you are saving the whole closure along with it