Blocks, Procs, and Lamdas: A Tour of Anonymous Functions in Ruby

Great news! Ruby has several ways of creating and passing around anonymous functions. Key language features like the Enumerable module would not be possible without this capability.

You might not even realize that when you are using a function that takes a block, you have just written an anonymous function. An anonymous function is exactly what it sounds like: a function with no name.

1
2
  %w(do re mi fa so la ti).map! { |note| note.capitalize }
  # => ["Do", "Re", "Mi", "Fa", "So", "La", "Ti"]

In this example, the { |note| note.capitalize } bit is the anonymous function. Used in this way the {} characters are block literals, passing function expecting one variable to the higher-order map! method.

Our own methods that take blocks

We can pretty easily write our own methods that accept blocks like this.

1
2
3
4
5
def block_caller(&block)
  puts "Hello from inside block_caller"
  block.call
  puts "About to leave block_caller"
end

Which we can use like this

1
2
3
4
5
6
7
block_caller do
  puts "Hello from inside the block"
end
# Hello from inside block_caller
# Hello from inside the block
# About to leave block_caller
# => nil

We use blocks expecting an argument in a very similar way.

1
2
3
4
5
6
7
8
def greeting(name, &block)
    block.call(name)
end

greeting("Mao")      { |name| "Ni hao, #{name}!"}
# => "Ni hao, Mao!"
greeting("Adolf")    { |name| "Guten Tag, #{name}!"}
# => "Guten Tag, Adolf!"

Use yield for a nice performance boost

There’s an alternative syntax available to us when writing methods expecting blocks: the yield keyword. We should prefer it because benchmarking shows that yield is about 5x faster than block.call.

1
2
3
4
5
6
7
8
def greeting(name)
    yield name
end

greeting("Mao")      { |name| "Ni hao, #{name}!"}
# => "Ni hao, Mao!"
greeting("Adolf")    { |name| "Guten Tag, #{name}!"}
# => "Guten Tag, Adolf!"

Overcoming limitations of blocks with Proc

If you do a little experimentation, you might notice that this brace syntax is a syntactic sugar that can only be used after a method call.

1
2
[2] pry(main)> { |note| note.capitalize }
SyntaxError: unexpected '}', expecting end-of-input

There’s also no way to pass multiple blocks to a single function. So a very common idiom in other langauges like JavaScript is to pass multiple functions to be used in different circumstances. For example, when making an Ajax call it’s convenient to pass both a success and error callback so our code knows how to continue in both situations:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// example.js

function successCallback() {
  // Take care of business
}
function errorCallback() {
  // Do damage control
}

$.ajax({
  url: 'http://www.example.com/api/widgets',
  type: 'GET',
  success: successCallback,
  error: errorCallback
})

The equivalent ruby would be something like

1
2
3
def ajax(url, type, success, error)
  # ... where the magic happens
end

We can’t use blocks to send success and error callbacks to this method. To accomplish this type of feat with Ruby, we have to use Proc objects, which Ruby provides as a way of wrapping a block into an object that may be passed around and used in multiple places. This is useful to use because methods can accept an arbitrary number of object parameters.

The simplest possible example of a Proc would be something like this:

1
2
  capitalizer = Proc.new { |str| str.capitalize }
  capitalizer.call("obama") # => "Obama"

Using Proc and keeping in mind that blocks are closures, we can write functions that return Procs.

1
2
3
4
5
6
7
8
9
10
def make_counter()
  x = 0
  Proc.new { x += 1 }
end


counter = make_counter()
counter.call() # => 1
counter.call() # => 2
counter.call() # => 3

Using a proc where a block is expected

If we need to use a proc where a block is expected, we can use the & operator.

1
2
3
add_five = Proc.new { |x| x + 5 }
[1, 2, 3, 4].map &add_five
# => [6, 7, 8, 9]

Choose your own syntax

Because Ruby likes to have multiple ways to accomplish everything, we’ve got several different sytnaxes available to us for constructing Proc objects.

1
2
3
4
5
6
7
8
9
10
11
  # Create a Proc object directly
  Proc.new  { |x, y| x + y }

  # Use this Kernal method
  proc      { |x, y| x + y }

  # Or this Kernal method
  lambda    { |x, y| x + y }

  # Or the "stabby lambda" syntax
  -> (x, y) { x + y }

The Proc methods and lambda methods are almost exactly the same except for the strange way the return keyword is handled in procs created with Proc.new.

The “stabby lambda” syntax, though probably the ugliest of all, can do something that none of the others can and that is specify default parameters similar to a normal method declaration.

1
2
adder = -> (x=5, y=4) { x + y }
adder.call() # => 9

Handy!

Gimme that method

One final trick to have up your sleeve it the ability to reach inside an object and turn any method into a Proc.

1
2
3
4
5
6
7
8
9
10
11
class Pig
  def oink
    puts "Oink!"
  end
end

wilbur = Pig.new
oinker = wilbur.method(:oink).to_proc
oinker.call
# Oink!
# => nil

Summary

Amazing! That concludes the tour of ruby’s blocks, procs, and lambdas.

To summarize:

  • Use blocks for one-off inline anonymous functions.
  • Use Proc.new if you need to reuse a code multiple times or need to pass multiple functions as arguments to the same function.
  • Use -> if you want to specify default parameters for your anonymous function.