Ruby Proc: How to Use the Ruby Proc to Make Your Programs Better

rubyarrayRuby is a pure object oriented programming language. It was created in 1993 by Yukihiro Matsumoto of Japan, also known as Matz. Ruby is a general-purpose, interpreted programming language like PERL and Python. Ruby is a scripting language and it runs on a variety of platforms, such as Windows, Mac OS, and the various versions of UNIX. If you’re new to Ruby programming, you may want to take this beginners Ruby course first before moving ahead.

You know how everything in Ruby is an object, well, as it turns out that’s not quite true. Ruby blocks are not objects (read this tutorial to learn more about Ruby blocks). But you can turn them into objects without too much trouble. You can do this by wrapping the block in an instance of the Proc class. This is really great since it turns the block into a first class function, which in turn allows Ruby to support closures. Once a language has closures, you can do all sorts of interesting things like making use of various functional concepts. You can learn more about objects, blocks and closure in Ruby with this course.

Now, let us really understand how Procs work.

What are Ruby Procs?

Proc objects are blocks of code that have been bound to a set of local variables. Once bound, the code may be called in different contexts and still access those variables. A Proc can have one, none or many arguments. In this tutorial, we do a deep dive into Ruby procs. This is an advanced level concept, so you do require some basic prior Ruby experience. You may want to take this Ruby course before we move on.

Example 1

Here’s how Procedure can be defined:

fact = Proc.new{|n| n * n }
multiply = Proc.new {|x, y| x * y }

The code in the Proc object can be invoked by using the call method.

p fact.call(3)               #=>This will invoke ‘fact’ Proc and return 9
p multiply.call(4, 3)           #=>This will invoke ‘multiply’ Proc and return 12

Instead of using call, you can invoke the code using square brackets notation. The following are equivalent:

multiply.call(4, 3)
multiply[4, 3]

You can pass around Proc objects like any other object:

def gen_ fact (factor)
return Proc.new {|n| n*factor }
end
class sampleProc
    def sample
        factor2 = gen_times(2)   # factor in gen_fact proc will be replaced with value 2
        factor4 = gen_times(4)# factor in gen_fact proc will be replaced with value 4
p factor2.call(9)              # Call gen_fact proc and return value 18
        p factor4.call(9)             # Call gen_fact proc and return value 36
end
end

Procs play the role of functions in Ruby. It is more accurate to call them function objects, since like everything in Ruby they are objects. Such objects have a name in the folklore – functors. A functor is defined as an object to be invoked or called as if it were an ordinary function, usually with the same syntax, which is exactly what a Proc is. To understand these better, you can take this course which helps explain Ruby from scratch.

From the example and the definition above, it is obvious that Ruby Proc can also act as closures. A closure is defined as a function that refers to free variables in its lexical context. Note how closely it maps to the Ruby definition blocks of code that have been bound to a set of local variables.

There are three ways to create a Proc object in Ruby. Well, actually there are four ways, but the last one is implicit. Let’s tale a look at them.

Using Proc.new

This is the standard way to create any object, you simply need to pass in a block and you will get back a Proc object which will run the code in the block when you invoke its call method. Here’s an example:

proc_obj=Proc.new{|n| n * n }
proc_obj.call(3)
output: 9

Using the Proc Method in the Kernel Module

Being in the Kernel module, this method is globally available. It is basically equivalent to Proc.new in Ruby 1.9, but not in Ruby 1.8. In Ruby 1.8 the proc method is equivalent to lambda. As you may have guessed there is a difference between procs and lambdas (see below), so you need to be aware of whether you’re using Ruby 1.8 or 1.9. If you’re using 1.9 there is a way to find out if you’re dealing with a proc or a lambda. The Proc object lambda? method:

Example:

proc_obj = proc{puts “Inside the Procedure”}
proc_obj.call
puts”Is procedure object a lambda - #{ Proc_obj.lambda? }”

Output:

Inside the procedure
Is procedure object a lambda - false

If you’re in 1.8 version this method will not exist at all. As far as I am concerned, if you need to switch between different versions of Ruby, don’t bother with the proc method, just use Proc.new and you will never have an issue.

Using the Kernel lambda method

Once again, this is globally available being in the Kernel module, using this method will create a Proc object, but it will be a lambda as opposed to a proc.

Example:

proc_obj = lambda {puts “Inside the Procedure”}
proc_obj.call
puts”Is procedure object a lambda - #{ Proc_obj.lambda? }”

Output:

Inside the procedure
Is procedure object a lambda – true

The implicit way

When you write a method which will accept a block, there are two ways you can go about it. The first is to simply use the yield keyword inside your method. If there is a yield in a method, but there is no block you will get an error.

Example:

def sample_method
puts”Hello World”
yield
end
sample_method {puts”Hello America”}
sample_method

Output:

Hello World
Hello America
Hello World

The other way is to use a special parameter in your method parameter list. This special parameter can have the same name but you will need to precede it with an ampersand. The block you pass into this method will then be associated with this parameter, you will in fact no longer have a block – it will be a Proc object. You will simply need to call the Proc call method to execute the code in the block you passed in. The difference is, you can now return your block (or rather the Proc object) as the return value of the method, thereby getting your hands on a Proc object without having to use any of the above three methods explicitly.

Example:

def sample_method(&my_block)
puts”Hello World”
my_block.call
my_block
yield
end
block_var = sample_method {puts”Hello America”}
block_var.call

Output:

Hello World
Hello America
Hello America

Those are all the different ways to get a Proc object in Ruby (either a proc or a lambda).

More on Procs

Once you have created your first class function (in Proc form), there are a few things that you may want to do with it, such as calling it or comparing it to another Proc. As usual, Ruby makes all of this interesting. Let’s look at Proc equality first. You can compare procs or lambdas to each other, using the == method (just like with any other object). Unlike many other objects though, defining exactly the same proc twice will not make them equal.

Example:

string1=’Hello World’
string2=”Hello World”
puts” String are equal? - #{string1==string2}”
proc1=Proc.new{“Hello World”}
proc2=Proc.new{“Hello World”}
puts” Procs are equal? -  #{ proc1== proc2}”

Output:

String are equal? – true
Procs are equal? - false

There are only two ways that two procs or lambdas will be equal to each other. One way is to define two really simple procs that have the same object in them

Example:

proc1=Proc.new{“ String1”}
proc2=Proc.new{“ String1”}
puts” Procs are equal? -  #{ proc1== proc2}”

Output:

Procs are equal? – true

This is not really very useful. The other way that two procs will ever be equal is if they are clones of each other (one was created by using the clone or dup method on the other).

Example:

proc1=Proc.new{|x|“ Hello World”*x}
proc2= proc1.dup
puts” Procs are equal? -  #{ proc1== proc2}”

Output:

Procs are equal? – true

Let us now look at executing procs. You have already seen the call method; this is the most common way to execute a proc or lambda.

Example:

puts Proc.new{|x|“ Hello World”*x}.call(2)

Output:

Hello World Hello World

But, there are actually two other ways. The first is to use the array syntax, this works in both Ruby 1.8 and 1.9:

Example:

puts Proc.new{|x|“ Hello World”*x}.[2]

Output:

Hello World Hello World

The other is the dot syntax, which only works in 1.9.

Example:

puts Proc.new{|x|“ Hello World”*x}.(2)

Output:

Hello World Hello World

This syntax being 1.9 only will once again cause Netbeans to barf all over itself :). Both of those ways are nice and succinct, but I still recommend you use call; it is not that much longer and is much more readable, both for yourself and for others. The array syntax could be especially confusing, consider:

Some_var[2,3]

That could refer to an array, a string, a proc – without context it’s a bit too ambiguous.

We hope this tutorial has helped you understand the intricacies of Proc. If you’d like to get a better feel of this, our advanced course on Ruby programming can help you master it.