Recently I was asked a question about ‘& parameters’ when you define and/or call methods which take a block e.g.:
|  |  | 
As you pass this parameter around, sometimes the ampersand appears in front of it, but other times it doesn’t, seemingly with no rhyme of reason. As we dig into crazy metaprogramming or write various libraries, it is often hard to remember how confusing Ruby can be when you’re starting out. So, let’s dig into this a little more deeply and shed some light on what’s going on.
The Implicit Block
Methods in Ruby can take arguments in all sorts of interesting ways. One case that’s especially interesting is when a Ruby method takes a block.
In fact, all Ruby methods can implicitly take a block, without needing to specify this in the parameter list or having to use the block within the method body e.g.:
|  |  | 
This will execute without any trouble but nothing will be printed out as we’re not executing the block that we’re passing in. We can – of course – easily execute the block by yielding to it:
|  |  | 
This time we get some output:
| 1
 | hello | 
We yielded to the block inside the method, but the fact that the method takes a block is still implicit.
It gets even more interesting since Ruby allows to pass any object to a method and have the method attempt to use this object as its block. If we put an ampersand in front of the last parameter to a method, Ruby will try to treat this parameter as the method’s block. If the parameter is already a Proc object, Ruby will simply associate it with the method as its block.
|  |  | 
| 1
 | lambda | 
If the parameter is not a Proc, Ruby will try to convert it into one (by calling to_proc on it) before associating it with the method as its block.
|  |  | 
| 1
 | converted lambda | 
All of this seems pretty clear, but what if I want to take a block that was associated with a method and pass it to another method? We need a way to refer to our block.
The Explicit Block
When we write our method definition, we can explicitly state that we expect this method to possibly take a block. Confusingly, Ruby uses the ampersand for this as well:
|  |  | 
Defining our method this way, gives us a name by which we can refer to our block within the method body. And since our block is a Proc object, instead of yielding to it, we can call it:
|  |  | 
I prefer block.call instead of yield, it makes things clearer. Of course, when we define our method we don’t have to use the name ‘block’, we can do:
|  |  | 
Having said that; ‘block’ is a good convention.
So, in the context of methods and blocks, there are two ways we use the ampersand:
- in the context of a method definition, putting an ampersand in front of the last parameter indicates that a method may take a block and gives us a name to refer to this block within the method body
- in the context of a method call, putting an ampersand in front of the last argument tells Ruby to convert this argument to a Procif necessary and then use the object as the method’s block
Passing Two Blocks To A Method
It is instructive to see what happens when you try to pass a both a regular block and a block argument to a method:
|  |  | 
You get the following error message:
| 1
 | code.rb:56: both block arg and actual block given | 
It is not even an exception – it’s a syntax error!
Using Another Method As A Block
It’s also interesting to note that since you can easily get a reference to a method in ruby and the Method object implements to_proc, you can easily give one method as a block to another e.g.:
|  |  | 
| 1
 | world | 
Passing The Block Around
We now know enough to easily understand our first example:
|  |  | 
- we define blahto expect a block, insideblahwe can refer to this block asblock
- we define yaddato expect one parameter, this parameter would be referred to asblockinsideyadda, but it is not a block in that we could notyieldto it insideyadda
- fooalso expects a block and we can refer to this block as- blockinside- foo
- when we call yaddafrom withinblahwe pass it ourblockvariable without the ampersand, sinceyaddadoes not a expect a block parameter, but simply a regular method argument, in our case this regular method argument will just happen to be aProcobject
- when we call foofrom insideyaddawe pass it ourblockvariable, but this time with an ampersand sincefooactually expects a block and we want to give it a block rather than just a regular variable
It should now be much more obvious why the ampersand is used in some cases, but not in others.
The Symbol To Proc Trick
We should now also have a lot less trouble understanding the ‘symbol to proc’ trick. You’ve no doubt seen code like this:
|  |  | 
We know that this is equivalent to:
|  |  | 
But now we also make an educated guess as to why they are equivalent. We have a Symbol object (’:upcase’), we put an ampersand in front of it and pass it to the map method. The map method takes a block, and by using the ampersand we’ve told Ruby that we want to convert our Symbol object to a Proc and associate it with the map method as its block. It turns out that Symbol implements to_proc in a special way, so that the resulting block becomes functionally equivalent to our second example above. Of course these days Ruby implements Symbol#to_proc using C, so it’s not quite as nice looking as the examples you’ll find around the web, but you get general idea.
Anyway, hopefully this makes blocks and ampersands a bit more friendly. It’s definitely worth it to occasionally revisit the basics, I’ll try to do it more often in the future.
Image by Martin Whitmore
 
    

