Blocks and Procs in Ruby

14 May 2009 – Denver, CO

So, in addition to a minor re-org (took the last post of the front page and decided to just show a list of posts), I continued reading this awesome article. Here’s the distilled version.

Procs

A Proc, at its simplest, is a block of code that has been bound to a local variable, also known in various forms (some of these more accurate than other) as “function objects”, “functors” and “closures”. They act like any other “first-class” objects, can be passed around, stored in data-structures.

 
>> def foo(a, b)
>> a.call(b)
>> end
=> nil
>>  a = Proc.new {|param| puts "'a' being executed on param #{param}"}
=> #<Proc:0x00587a14@(irb):4>
>> b = "hello"
=> "hello"
>> foo(a, b)
'a' being executed on param hello
=> nil

In the above example, we’ve created a proc “a” which accepts params “param”. When we pass both to foo, it simply calls “a” and passes “b” in.

We have a choice when creating procs – between “Proc.new” and “lamdba”.

 
?> x = lambda {|y| puts y}
=> #<Proc:0x0057a24c@(irb):16>
>> x.call("hello")
hello
=> nil

In short, they differ slightly in how the return from methods (Proc.new created Procs will return immediately, lambda will not) and the fact that lambda does parameter checking and Proc.new does not.

Methods

Methods are blocks of code, bound to an object, that have access to its instance variables. The interesting thing about a method here is that you can define ‘top-level’ methods, which is implicitly bound to the Object class.

 
>> def s; puts "s"; end
=> nil
>> p Object.methods
["inspect", "private_class_method", "const_missing", "clone", 
"method", "public_methods", "public_instance_methods", ...
=> nil
>>

And we can also dynamically call the method using send (we can pass either a String or the Symbol for the method name).

 
?> o = Object.new
=> #<Object:0x5e9cf0>
>> o.send(:s)
s
=> nil
>>

Blocks

A Block is a (lets called it ‘uninstantiated’) proc. Its the block of code for example in the braces after the lambda command.

 
>> x = lambda {"puts i am a proc"}
=> #<Proc:0x005f0924@(irb):1>
>> def f(func)
>> func.call
>> end
=> nil
>> f(x)
=> "puts i am a proc"
?> def g
>> yield
>> end
=> nil
>> g {"i am a block, implicitly turned into a proc when passed to method"}
=> "i am a block, implicitly turned into a proc when passed to method"

On a final note, I’ve been using this sidebar which is truly awesome.