Some time ago I used to think that the
& unary operator in Ruby could be
used to create a
Proc object. It turns out I was slightly wrong.
I think I’m not alone here as apparently the
&: operator even gets the name
of symbol to proc
name is misleading in several ways:
- It’s not really an operator,
&:is a combination of the
&operator followed by a symbol definition.
&:upcaseis exactly the same as
- You can’t use it to create a
Procobject, this is explained this with detail below.
Using it at method invocation (proc to block)
To be precise, the operator does create a
Proc object when used with a
symbol, but it’s just because Ruby needs to do this internally as part of
the process to build the block which will be passed to the method being
invoked. As this proc is internal, we can’t access it from our Ruby code.
What the operator really does is to pass its only operand as a block to the method we’re invoking. It converts something to a block.
Take the following snippet for example:
%w(a b c).map(&:upcase) # => ["A", "B", "C"]
When this is executed, Ruby will pass whatever follows the
& operator as
the block for the method. But in this case we have a
It’s pretty obvious how to convert a
Proc into a block. Both things are
almost the same.
It’s not so obvious how to convert a
Symbol to a block. Here’s where
:to_proc comes in. When the object given to the operator isn’t a
:to_proc will be invoked on the parameter to produce a proc that
will later be converted to a block.
So, the snippet can be rewritten as the following equivalent:
%w(a b c).map(&(:upcase.to_proc)) # => ["A", "B", "C"]
Notice that we haven’t used the operator to build the proc, but to build the block.
Using it at method definition (block to proc)
Just for completeness, I’ll mention that the same operator can be used in a different context to convert a block to a proc.
In the following example, the operator is used in the params of a method definition:
def repeat_twice(&what) what.call what.call end repeat_twice do puts rand(10) end
The code will show a couple of random numbers on screen, but what’s most
important here is that the block defined with a
do ... end becomes a proc
what inside the method.
repeat_twice is invoked, we’re sending a block which will be
converted to a proc and added to the table of local variables when the method
In this case we did create a proc, but we didn’t use any
Symbol at all.
In summary, you can’t use the symbol to proc operator to create a proc from a symbol.
This looks like a subtle thing, but hopefully I’ve helped someone to avoid the confusion I had.
I guess block operator is a better name, because what it really does is to convert procs to blocks and vice-versa.
What do you think?