Make delicious recipes!

Procs, blocks and yield in ruby




Proc: A proc in ruby is like a closure in JavaScript - It is a function definition that has been bound to local variables. Example:
def adder_proc_creator (increment)
  Proc.new {|n| n + increment}
end
adder1 = adder_proc_creator(1)
adder5 = adder_proc_creator(5)
adder1000 = adder_proc_creator(1000)

adder1.call(10)
=> 11
adder5.call(10)
=> 15
adder1000.call(10)
=> 1010

So adder1, adder5 and adder1000 are all function definitions bound to the local variable of the function adder_proc_creator.
Attaching a function definition to local variables in this manner is useful to templatize function-definitions in some cases.



Block: A block in ruby is same as a block in languages like C and Java - It is just a bunch of statements grouped together.
Syntax of a method is defined as:
def <method-name> <block>

The reason why blocks' understanding is more important in ruby is because a block can be appended to a method call as:
<method-call> <block>

And when that happens, Ruby automatically converts the block to a Proc object without an explicit name.
The called method can execute the block by using the yield statement.

Example:
def my_method
  puts "1"
  yield
  puts "2"
end

# Call the above method with a block
my_method {puts "3"}
=> 1
=> 3
=> 2

You can call yield multiple times and with arguments:
def my_method
  puts "1"
  yield 5
  puts "2"
  yield 10
  puts "3"
end

my_method {|n| puts "#{n}"}
=> 1
=> 5
=> 2
=> 10
=> 3


The block can have multiple lines:
my_method do |n|
  n = n+100
  puts "#{n}"
end

=> 1
=> 105
=> 2
=> 110
=> 3


What if you want to execute more than one blocks?
For that you need to use either Procs or lambdas.
proc1 = Proc.new {|x| puts "#{x} from 1"}
proc2 = Proc.new {|x| puts "#{x} from 2"}
proc3 = Proc.new {|x| puts "#{x} from 3"}

def my_method (p1, p2, p3) 
  p1.call("hello")
  p2.call("hello")
  p3.call("hello")
end

my_method proc1,proc2,proc3
=> hello from 1
=> hello from 2
=> hello from 3

Lambdas are the same as proc for most purposes:
proc1 = lambda {|x| puts "#{x} from 1"}
proc2 = lambda {|x| puts "#{x} from 2"}
proc3 = lambda {|x| puts "#{x} from 3"}

my_method proc1,proc2,proc3
=> hello from 1
=> hello from 2
=> hello from 3

So is lambda an alias for Proc? Not really.
One important difference is that return inside a proc will return the control flow from the enclosing function too where as a return inside a lambda will only terminate the lambda.


What if a function expects a block and we want to pass it a proc?
This can be resolved by using ampersand to convert proc to block or block to proc.
def my_method
  puts "1"
  yield 5
  puts "2"
  yield 10
  puts "3"
end

proc1 = Proc.new do |x|
  y = x*x
  puts "#{y}"
end
my_method &proc1
=> 1
=> 25
=> 2
=> 100
=> 3







Like us on Facebook to remain in touch
with the latest in technology and tutorials!


Got a thought to share or found a
bug in the code?
We'd love to hear from you:

Name:
Email: (Your email is not shared with anybody)
Comment:

Facebook comments:

Site Owner: Sachin Goyal