codedecoder

breaking into the unknown…

proc and lambda in ruby

2 Comments

In this post I have explained about ruby block, read it if you are not clear about block before proceeding further. Here we will try to understand Proc in ruby. ruby documentation define it as below .

“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.”

Forget it if you do not understand a bit of the definition. I will explain it in simpler way as we proceed. To get a better idea of any programming concept you must ask two question : why and when .

So here we have the question, why to use Proc and when to use Proc. Iet us figure it out. I can’t visualize any better scenario, so I will stick to the case when we have to welcome peoples from different part of India.
Let us write our code in proc_demo.rb file.

Example 1:  Creating Proc object, storing it in  variables and passing it to a method

punjab = Proc.new do |person|
  puts "Hi....#{person}...how are you?"
  puts "I welcome you as per punjab tradition"
  puts "I will serve you makki di roti with sarson di saag"
end

tamil = Proc.new do |person|
  puts "Hi....#{person}...how are you?"
  puts "I welcome you as per tamil tradition"
  puts "I will serve you idli and curd rice"
end

mumbai = Proc.new do |person|
  puts "Hi....#{person}...how are you?"
  puts "I welcome you as per mumbai tradition"
  puts "I will serve you bada pav and pav bhaji"
end

def welcome(guest, proc_obj=nil)
  puts "I am the head of family"
  proc_obj.call(guest) if proc_obj
  puts "Let me introduce you to my family"
end

puts "*********OUTPUT of welcome('arun' , punjab)*************"
welcome("arun" , punjab) # arun is the local variable and punjab the variable containing proc object
puts "*********OUTPUT of welcome('arun' , mumbai)*************"
welcome("arun" , mumbai) # arun is the local variable and mumbai the variable containing proc object
puts "*********OUTPUT of welcome('arun' , mumbai)*************"
welcome("rama swamy" , tamil) # rama swamy is the local variable and tamil the variable containing proc object

run this file from your terminal with ruby keyword as below and see the output .

arun@arun-yadav:~$ ruby   “/home/arun/proc_demo.rb”
*********OUTPUT of welcome(‘arun’ , punjab)*************
I am the head of family
Hi….arun…how are you?
I welcome you as per punjab tradition
I will serve you makki di roti with sarson di saag
Let me introduce you to my family
*********OUTPUT of welcome(‘arun’ , mumbai)*************
I am the head of family
Hi….arun…how are you?
I welcome you as per mumbai tradition
I will serve you bada pav and pav bhaji
Let me introduce you to my family
*********OUTPUT of welcome(‘rama swamy’ , tamil)*************
I am the head of family
Hi….rama swamy…how are you?
I welcome you as per tamil tradition
I will serve you idli and curd rice
Let me introduce you to my family

We can summarize below things about Proc from the above example.

=> Proc object can be created in two way : Proc.new or lambda. we have used Proc.new above, but you can use lambda also. lambda is stricter implementation of Proc object. we will come to the difference later on.
=> Proc are object which wrap in the block passed to it
=> once created proc object can be stored in a variable, can be used in any method directly, can be passed as a argument to any method
=> the block within proc object can be executed by call() method
=> the proc object bind itself to the local variables of the method in which it is called. for example : in above output you can see that the person name passed to the method is used by the proc object.
=> Proc object look similer to method in its implementation, but looking deeper, below is the major difference
        -> method can’t be passed to another method but proc can be passed to any method
        -> method can return a value but can’t return another method but Proc can return another method.

=> So we can conclude that, Proc provide better flexibility as compared to a method, which explain why we should use it. Now coming to when…we should use Proc whenever, a piece of code within any method need to behave differently in different situation. In above case the welcome message varies according to state from which the person is coming.

Example 2: Creating Proc object directly within the method.

As I have mentioned above we can create Proc object in two ways. Above example used Proc.new, so now we will use lambda. In whichever way you are creating the Proc object, you should always pass a block to it. If NO block is passed to proc object, It will try to execute the block passed to the method within which it is called. If the method also do not have any block passed to it, It will throw error when proc object is called. Let us illustrate it . write below code to proc_demo.rb file.

def welcome(guest)
  puts "I am the head of family"
  message = lambda # proc object is created with lambda but no block is passed
  message.call(guest) # the proc object executed with call()
  puts "Let me introduce you to my family"
end

puts "*********OUTPUT of method call with a block*************"
welcome("arun"){|person| puts "Hi #{person}.....how are you"}
puts "*********OUTPUT of method call without a block*************"
welcome("arun")

run the above ruby file and see the output :

arun@arun-yadav:~$ ruby /home/arun/proc_demo.rb
*********OUTPUT of method call with a block*************
I am the head of family
/home/arun/Documents/books/learn_ruby/proc_demo.rb:4: warning: tried to create Proc object without a block
Hi arun…..how are you
Let me introduce you to my family
*********OUTPUT of method call without a block*************
I am the head of family
/home/arun/Documents/books/learn_ruby/proc_demo.rb:4:in `lambda’: tried to create Proc object without a block (ArgumentError)
from /home/arun/Documents/books/learn_ruby/proc_demo.rb:4:in `welcome’
from /home/arun/Documents/books/learn_ruby/proc_demo.rb:12:in `’

So here we have created the Proc object directly within the method. you can see that if block is not passed to proc object and also not available in method where it is called it throw error.

Example 3: Method which return Proc object.
In both the example above, you can see that the Proc object is called within the method itself. But you can make any method to return a Proc object. It is also a major point which emphasise why and when we should use a Proc instead of method. Note that a method can return a value but can’t return another method, but it can return a Proc object.

def multiply_val(num)
  return Proc.new{ |n| n*num}
end

puts "**OUTPUT with different argument value of multiply_val() and call()**"
puts multiply_val(3).call(5)
puts multiply_val(3).call(12)
puts multiply_val(7).call(12)

Now see the output of above program.

arun@arun-yadav:~$ ruby /home/arun/proc_demo.rb
**OUTPUT with different argument value of multiply_val() and call()**
15 # multiplication of 3 passed to the method and 5 passed to the block in Proc object
36 # multiplication of 3 passed to the method and 12 passed to the block in Proc object
84 # multiplication of 7 passed to the method and 12 passed to the block in Proc object

So here, you can see that Proc object is called not within the method but outside it as the method is returning a Proc object. when you write multiply_val(3), it return a Proc object which is bounded to the local value 3 passed to the method. Then you simply execute that object with call()

DIFFERENCE BETWEEN PROC and LAMBDA :

As you have seen above, both Proc.new and lambda is used to create Proc object. lambda is stricter implementation of Proc object. These are the main defference:

=> lambda raise exception if required number of argument is not passed .

NOTE : You can use proc for Proc.new . proc is shorthand of Proc.new

A Proc object generated by proc ignores extra arguments.
proc {|a,b| [a,b] }.call(1,2,3) # output => [1,2]

A Proc object generated by proc provides nil for missing arguments.

proc {|a,b| [a,b] }.call(1) # output => [1,nil]

A Proc object generated by proc expands a single array argument.

proc {|a,b| [a,b] }.call([1,2]) # output => [1,2]

A Proc object generated by lambda doesn’t have such tricks.
It throw ArgumentError exception.

lambda {|a,b| [a,b] }.call(1,2,3) # output => ArgumentError
lambda {|a,b| [a,b] }.call(1) # output => ArgumentError
lambda {|a,b| [a,b] }.call([1,2]) # output => ArgumentError

=> the use of return in proc and lambda

lambda returns out of itself, and proc returns out of itself AND the function that called it. let us illustrate it.

def proc_return
  proc_obj = proc do 
    puts "Iam in Proc object created with proc"
    return "Hello"
  end
  puts proc_obj.call
  puts "How are you"
end

def lambda_return
  lambda_obj = lambda do 
    puts "Iam in Proc object created with lambda"
    return "Hello"
  end
  puts lambda_obj.call
  puts "How are you"
end

puts "output of proc_return"
proc_return

puts "output of lambda_return"
lambda_return

Now run the file to see the output

arun@arun-yadav:~$ ruby /home/arun/proc_demo.rb
output of proc_return
Iam in Proc object created with proc
output of lambda_return
Iam in Proc object created with lambda
Hello
How are you

So you can easily see that, when return called in a Proc object control immediately exit from the proc object as well as the method calling the proc object and so in out put no line after the return statement get printed. But you can see that lambda behave as expected, it return from proc object and other lines in the method get executed.

NOTE : proc is full of surprise. always use lambda to implement a Proc object

REFERENCE :

http://www.ruby-doc.org/core-2.0.0/Proc.html #ruby proc documentation

http://stackoverflow.com/questions/626/when-to-use-lambda-when-to-use-proc-new # comparison between Proc.new and lambda.

Author: arunyadav4u

over 7 years experience in web development with Ruby on Rails.Involved in all stage of development lifecycle : requirement gathering, planing, coding, deployment & Knowledge transfer. I can adept to any situation, mixup very easily with people & can be a great friend.

2 thoughts on “proc and lambda in ruby

  1. In the lambda_return method in the section “=> the use of return in proc and lambda”, shouldn’t it be

    lambda_obj = lambda do
    instead of
    lambda_obj = proc do
    ?

    Thanks for this great tutorial!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s