Take me home

Procs, blocks and anonymous functions

Written by August Lilleaas, published November 08, 2008

This is a Big Picture™ post. I will attempt to give you a thorough understanding of how blocks and procs works in Ruby by showing examples and explaining basics. I will also show some examples from other languages, namely Javascript and Lua, in order to really expand on the Big Picture™ in this article.

Storing pieces of code

In Ruby, you can store pieces of code and execute them on demand; methods. You define the method, add code to the method body, and run the method whenever you want.

In addition to methods, there is another way in Ruby to store code that you can call later; procs.

say_hello = Proc.new { puts "Hello!" }

Contrary to what you might expect, the puts doesn’t run. Ruby only stores the code inside the proc, it doesn’t run it. Not yet, at least. It runs when we tell it to. Let’s run it right away. Remember, we stored the proc in the say_hello variabe.

say_hello.call
# => "Hello!"

So, there you go. That’s what procs are, and that is all there is to it. But how the fsck is this useful to anyone? Why not just use methods?

Organizing your code with procs

Procs are useful code organization tools. Let’s say that you want to calculate the running time for a few code snippets, in order to benchmark them. To do this elegantly, you want to be able to call a method and pass some code to it, and have the execution time returned.

Here’s how you can use procs to do just that:

def time(a_proc)
  start = Time.now
  a_proc.call
  puts Time.now - start
end
 
time(Proc.new { code_here })
time(Proc.new { more_code_here })

The execution times of the code inside the procs will be neatly displayed as you run this code. Try it yourself, right now! You can use sleep(2), 1000.times { 5 + 5 }, or anything else you might want to speed test.

Blocks!

In addition to method arguments, a method can also take a block. Passing a block is essentially the same as passing a proc, except that the syntax is different (and nicer), and you don’t have to type as much. Other than that, procs and blocks are essential the same thing: code that you can call later on.

def time
  start = Time.now
  yield
  puts Time.now - start
end
 
time { code_here }
time { more_code_here }

Looks a lot nicer, doesn’t it? Upon further inspection, it is easy to see where procs and blocks differs. Comparing the two examples, we can see that the time method no longer takes an argument. A block is a special internal thing in Ruby, so you don’t need to specify a method argument for the block. Also, we use yield instead of a_proc.call. yield is a special keyword in Ruby, telling Ruby to call the code in the block that was passed to that method. Lastly, actually passing the code to the method has a different syntax. No parentheses, because the block is not an argument. No Proc.new either, because we aren’t creating a proc, we are passing a block.

Passing arguments to procs and blocks

When you yield or call, you can pass arguments to the proc or block at the same time. A dumb example:

def dumb_hello_world_test
  yield(5)
end

dumb_hello_world_test {|i| puts i * 2 }
# => 10

my_silly_proc = Proc.new {|name| puts name.upcase }
my_silly_proc.call("August Lilleaas")
# => "AUGUST LILLEAAS"

You have probably seen blocks taking arguments before: each, map and other enumerable methods does this.

[1, 2, 3].map {|i| puts i * 2 }
# => 2
# => 4
# => 6

That’s right: map takes a block. The block gets an argument: the number in the array. Now, for something hardcore. Let’s play with an implementation of Array#each.

class Array
  def each
    i = 0
    while(i < self.length) do
      yield(self[i])
      i += 1
    end
  end
end

my_array = ["a", "b", "c"]
my_array.each {|letter| puts letter }
# => "a"
# => "b"
# => "c"

We iterate the items in the array, and call the block — yield — for every item in the array. When we yield, we pass the current array iteration to the block.

The big picture: blocks and procs in other languages.

Ruby isn’t the only language that lets you pass around chunks of code. Here are some examples in Javascript and Lua. Despite their obvious use case differences, these two languages are pretty similar.

Remember how you can use both methods and procs/blocks to store chunks of code in Ruby? In JS/Lua, methods and procs/blocks are replaced by functions. This is possible because, unlike Ruby, you can refer to a function by name without calling it, or create anonymous functions.

// javascript
var sayHello = function(){
  alert("Hello, World!");
}
 
sayHello    // a reference
sayHello()  // calling it
 
-- lua
local function sayHello()
  print("Hello, World!");
end
 
sayHello    -- a reference
sayHello()  -- calling it

Again, unlike Ruby, sayHello won’t execute the function, while sayHello() will. Let’s create an implementation of the time method in JS and Lua.

// javascript
var time = function(callback){
  var start = new Date();
  callback();
  alert(new Date.getTime() - start.getTime());
}
 
time(function(){
  // run some code here..
});
 
-- lua
local function time(callback)
  local start = os.time();
  callback();
  print(os.time() - start);
end
 
time(function()
  -- run some code here..
end);

As you can see, you can pass an anonymous function definition directly to the two time functions, as an argument — similar to the way you Ruby lets you pass procs as method arguments.

Just to elaborate, and as mentioned, you can pass a reference to a function as well as an actual function definition.

time(sayHello)

And just to make sure you’re with me: time(sayHello()) will break miserably. sayHello will execute before time, which causes time to use whatever executing sayHello returns, instead of the function reference.

Lastly, a Ruby recap. In Ruby, foo and foo() are equivalents.

def say_hello
  puts "Hello, World!"
end

say_hello
# => "Hello, World!"
say_hello()
# => "Hello, World!"

So, while other languages are able to pass around chunks of code by using references to other functions, Ruby doesn’t allow that. Ruby has a separate feature for this, though; procs and blocks.

Relevant boring facts: Blocks to procs to blocks

You can convert a block passed to a method into a proc by using special syntax for this.

def time(&block)
  puts block
end

time
# => nil
time { foo }
# => #<Proc:0x00029bbc>

You can also do this the other way around: pass a proc to a method and make it look as if you passed a block.

def time
  yield
end

my_proc = Proc.new { puts "I was called!" }
time(&my_proc)
# => "I was called!"

The ampersand is the key here, which tells Ruby that block and my_proc isn’t a method argument but a reference to the block passed to that method. Leave out the ampersand, and it’ll be treated as a regular method argument.

def time(block)
  puts block
end

time { foo }
# => ArgumentError: wrong number of arguments (0 for 1)
# Because the ampersand was left out in the method definition, the method now expects an
# argument, and it is given none (a block is not a method argument).

def time
  yield
end

time(my_proc)
# => ArgumentError: wrong number of arguments (1 for 0)
# Because the time method doesn't take any arguments, and without the ampersand, my_proc 
# is passed as a regular method argument.

Block syntax

do ... end and { ... } are equivalents. These two calls to time are identical.

time { code_here }
  
time do
  code_here
end

The ideom is to use do ... end on multi-line blocks, and { ... } for one-liner blocks. It is entirely up to you, though. Following the ideom is recommended, but Ruby doesn’t enforce it.

A note on lambdas

Short answer: lambda { foo } and proc { foo } is essensially the same thing, you can use both interchangeable in your code.

There is two differences, though: One is how it handles return. I suggest reading this article.

The other is how it handles arguments. This is really lame and strange. lambda and proc are equivalents, while Proc.new differs. You’d think Proc.new and proc were equivalents, but they aren’t. I’ll let this code speak for itself.

a_lambda = lambda {|a| a.inspect }
puts a_lambda.call
# => nil
puts a_lambda.call("foo", 5)
# => ["foo", 5]

sumlam = lambda {|a, b| a + b }
sumlam.call
# => ArgumentError: wrong number of arguments (0 for 2)

sumproc = proc {|a, b| a + b }
sumproc.call
# => ArgumentError: wrong number of arguments (0 for 2)
sumproc.call(4, 5)
# => 9

orlyproc = Proc.new {|a, b| a + b }
orlyproc.call
# => NoMethodError: undefined method `+' for nil:NilClass
orlyproc.call(4, 5)
# => 9

Questions or comments?

Feel free to contact me on Twitter, @augustl, or e-mail me at august@augustl.com.