Method References in Ruby
April 10th, 2014Today I was writing some Ruby code for filtering arrays when I recalled that Ruby has a shorthand notation to pass a method by its name (as a symbol). I’m writing this post to help me remember, while I figure out how it really works.
Say, for example, that we need to select the odd numbers from a sequence. Of course we could pass a block to do that.
But we can also pass a symbol, prefixed with an ampersand. While not actually accurate (in a few minutes you’ll see why), this is what I call a method reference.
Personally I prefer the latter form as it’s a better representation of the essence that I want my code to do: from range 1 to 9 select only odd numbers.
How does it work?
When Googling for information on the ampersand unary operator in Ruby, I first found a few blog posts and Stack Overflow answers that told me that &
calls to_proc
on a given object. That would be convenient, although it implies that this would probably only work for methods that accept both a block or a proc. Let’s worry about that later.
First try and see if this works. If &
would call to_proc
on the symbol I should be able to pass a proc myself, too.
Whoops! That didn’t work too well. What’s even more interesting is that if I just put the ampersand in front, the code runs.
So maybe these first hits weren’t actually correct about things. At this point it seems more likely that ampersand turns a proc into a block. And given any object, it will get a proc by calling to_proc
first.
To see how my new theory works out I use a custom object that answers to to_proc
. Because Ruby’s blocks are special things that cannot be created or assigned to variables, I cannot simply capture the resulting value of &:foo
. Let’s give it a try.
Awesome! However, this doesn’t really confirm that the ampersand in fact turns the proc into block, only that actually to_proc
is called on the object.
To check that the ampersand turns the proc into a block I use a function that yields.
While passing a proc obviously won’t work.
Tentatively my conclusion is that the ampersand unary operator takes a duck-type of a proc (i.e. an object that responds to to_proc) and returns a block. If you see any flaws in this, don’t hesitate to let me know.