Thursday, September 9, 2010

Ruby Procs

I've just started learning Ruby in conjunction with the Ruby on Rails framework. Going through my first Rails tutorial, I found myself trying to understand the respond_to code in my generated controllers. This lead me to an examination of Ruby's block and proc constructs. While experimenting I discovered that there's at least two ways to declare blocks, and three ways to instantiate Ruby Procs. Counting the 2 block variations, you may see 6 permutations of Ruby Proc instantiation.

strings = ["Foo", "Bar", "Blah"];

# Below is 6 functionally similar first-class Procs defined in different ways.
procs = []
procs.push(lambda {|x| print x})
procs.push(lambda do |x| print x end)
procs.push( {|x| print x})
procs.push( do |x| print x end)
procs.push(proc{|x| print x})
procs.push(proc do |x| print x end)

procs.each {|i| puts i}
# Prints:
#<Proc:0x0000010086a8c0@blocks_and_procs.rb:5 (lambda)>
#<Proc:0x0000010086a898@blocks_and_procs.rb:6 (lambda)>

for i in 0..5
print " of proc #{i}: " &procs[i]
print "\n"
# Prints of proc 0: FooBarBlah of proc 1: FooBarBlah of proc 2: FooBarBlah of proc 3: FooBarBlah of proc 4: FooBarBlah of proc 5: FooBarBlah

# And here's the inline methods of passing a block.
print " of do block:" do |x| print x end
print "\n"

print " of {} block:" {|x| print x}
print "\n"
# Prints of do block:FooBarBlah of {} block:FooBarBlah

You may notice that a dump of my procs yields two instances which note they're lambdas. Lambda and have subtle differences in their argument checking and the way returns are handled from the Proc. See this link for more detail.

Admittedly, I couldn't help but be a little disappointed that there's so many ways to accomplish the same simple thing with Ruby. Particularly when one of its prized attributes is a syntax that is simple and consistent.