I’m going to assume that you are already familiar with the double ampersand
operator in Ruby - the logical AND. This post is going to focus on all uses of
the single ampersand operator. & can be quite confusing because it has a
different meaning depending on the context in which it’s used. In fact, both
&object) and binary (
object & object) operations have meaning in
Ruby. To understand these let’s look at the uses of & in core Ruby.
In Ruby 1.9.3 there are three uses for the binary ampersand operator.
Bitwise AND is the binary bit-by-bit equivalent of boolean AND. So binary
101 & 100 = 100 and binary
101 & 001 = 001. & is defined as a bitwise AND
Process::Status and simply converts the
integer into a binary representation and performs a bitwise AND on that
Process::Status converts the process status number to a
Fixnum and uses that to perform the operation.
The result of this operation can be clearly seen by converting the numbers to their binary representations.
Possibly the simplest use of the binary & operator is in the
Array class. &
is the set-intersection operator, which means the result is a collection of the
common elements in both arrays.
TrueClass binary & is the equivalent of
the boolean AND. Keep in mind this does not work like the && operator, since it
is only defined on these three classes.
When the binary ampersand operator is invoked (
First & Second) Ruby executes
the definition from the first object (
First#&). You can write your own binary
ampersand method easily. When I do, I try to keep the first two core Ruby uses
in mind - bitwise AND and set intersection. I don’t like using logical AND
because it is already covered by the
&& operator and is only defined on
nil, which are special classes. Here is a custom example
that works like set intersection.
The Unary & is a little more complex. It is almost the equivalent of calling
#to_proc on the object, but not quite. To understand it let’s go over some
background first. In Ruby you have two kinds of code blocks, Blocks and Procs.
The two are very closely related but have some important differences. You can
define and reference Procs and assign them to variables. Blocks are always
related to a method call and can’t be defined outside of that context. The way
you tell them apart is that Procs are always preceded by
->() when they are defined.
All methods have one and only one implicit Block argument, whether you use it or
not. You can access it by calling
yield in the method body.
Blocks are pretty useless outside of function calls though, for instance you can’t just define one.
But you can define and reference Procs.
Procs fall into two categories. Procs that are
lambda?, lambda procs, and
Procs that aren’t, simple procs. Lambdas are defined using
and whereas simple procs are defined using
I’m not going to delve into the details of lambdas and simple procs, but there
are two basic differences and it’s important to know that they exist. The first
is that lambdas are strict argument checkers, like methods, they can throw an
ArgumentError exception. Simple procs will just ignore incorrect, extra or
fewer argument combinations. The second is that lambdas act like methods
regarding their return status - they can return values just like methods. When
you try to return a value from a simple proc you end up with a
Now back to our unary ampersand operator. Since both Blocks and Procs are useful, it’s convenient to be able to switch between them - enter &.
&object is evaluated in the following way:
lambda?status of the object.
Let’s examine each of these steps individually.
The simplest example of this is when we want to have access to the block we pass to a method, instead of just calling yield. To do this we need to convert the block into a proc.
lambda? status of the object.
This is an extremely useful case of the & operator. For instance, we know that
Array#map takes a block, but say we have a proc that we want to re-use in
multiple map calls.
Keep in mind that the operator also preserves the
lambda? status of the
original block. That’s kind of neat because it means we are able to pass lambdas
(not simple procs) as blocks. That means we can impose strict argument checking
in our blocks and we can have them return values using the
return keyword. The
only exception to this preservation is methods, which are always lambdas
regardless of how they are defined.
#to_procon the object and then converts it into a block.
This is where the magic really happens because it makes passing objects to
functions in the place of blocks very simple. The most common case of this is
probably calling into
Array#map with a symbol.
This works because calling
Symbol#to_proc returns a proc that responds to the
symbol’s method. So the
:to_i symbol is first converted to a proc, and then to
a block. This is kind of cool because we can create our own
Hopefully this post has clarified the binary and unary ampersand operator in Ruby. It’s a fun operator. In the binary form it can provide us with a shorthand way of doing bitwise AND and set intersection like operations. In the unary form it provides us with some powerful functionality for converting blocks and procs.