Procs and the Four Ways of Calling Them

Unlike the language named after a certain serpent, Ruby embraces TMTOWTDI (pronounced as Tim Toady), or There’s more than one way to do it. The calling of Procs is a wonderful example. In fact, Ruby gives you four different ways:

  1. Proc#call(args)

  2. .(args)

  3. Threequals

  4. Lambdas

Fire up irb. Let’s begin by creating a very simple Proc:

 >>​ p = proc { |x, y| x + y }
 =>​ ​#<Proc:0x007ffb12907940@(irb):1>

There are two things to notice here. First, the return value tells you that a Proc has been created. Second, Ruby provides a shorthand to create Procs. This is really a method in the Kernel class:

 >>​ p = Kernel.proc { |x, y| x + y }
 =>​ ​#<Proc:0x007ffb12907940@(irb):1>

Of course, since Proc is just like any other class, you can create an instance of it the usual way:

 >>​ p = Proc.new { |x, y| x + y }
 =>​ ​#<Proc:0x007ffb12907940@(irb):1>

Now you know how to create a Proc. Time to make it do some work. The first way is to use Proc#call(args):

 >>​ p = proc { |x,y| x + y }
 
 >>​ p.call(​"oh"​, ​"ai"​)
 =>​ ​"ohai"
 
 >>​ p.call(4, 2)
 =>​ 6

In fact, this is my preferred way of invoking Procs because it conveys the intent of invocation much better than the alternatives, which are presented next.

Ruby provides a shorthand for the call(args) method: .(args). Therefore, the previous example could have been rewritten as such:

 >>​ p = proc { |x,y| x + y }
 >>​ p.(​"oh"​, ​"ai"​)
 >>​ p.(4, 2)

Here’s an interesting Ruby tidbit. Turns out, the .() syntax works across any class that implements the call method. For example, here’s a class with only the call method:

 class​ Carly
 def​ call(who)
 "call ​​#{​who​}​​, maybe"
 end
 end
 
 c = Carly.new
 c.(​"me"​) ​# => "call me, maybe"

You should avoid using .() if you can, because this could potentially confuse other people who might not be familiar with the syntax.

Ruby has an even quirkier syntax for invoking Procs:

 p = proc { |x,y| x + y }
 p === [​"oh"​, ​"ai"​]

The === operator is also known as the threequals operator. This operator makes it possible to use a Proc in a case statement. Look at the following code:

 even = proc { |x| x % 2 == 0 }
 case​ 11
 when​ even
 "number is even"
 else
 "number is odd"
 end

Here, even, when given a number, returns true or false depending on the case statement. For example:

 >> even = proc { |x| x % 2 == 0 }
 >> even === 11
 => ​false
 >> even === 10
 => ​true

Note that invoking a Proc that expects a single argument this way is incorrect and results in a confusing error message:

 >> even = proc { |x| x % 2 == 0 }
 >> even === [11]
 NoMethodError: undefined method ​`%' for [11]:Array
  from (irb):1:in `​block ​in​ irb_binding​'

Next, let’s look at lambdas and how they relate to Procs.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.118.163.250