Tropical Software Observations

16 October 2012

Posted by Anonymous

at 3:16 PM

0 comments

Ruby Block vs Proc.new vs Lambda vs method(:func) Summarized

There are many ways to pass code around in Ruby, so today I'm going to make a comparison between the 4 different ways. The first section, I will show the syntax of using each of them:
1. Block
2. Proc
3. Lambda
4. method(:func)
On the second section, I will compare the subtle differences they have.

A quick syntax comparison:
* note that the result is at the last section of each code *
1. Block

class String
def perform
yield self
end
end
#=== block ====
block_string = "Hey there, "
block_string.perform do |n|
puts n + "from a block!"
end
#=== Result ===
Hey there, from a block!
view raw block.rb hosted with ❤ by GitHub
2. Proc.new
class String
def perform code
code.call self
end
end
#===proc: storing into a variable====
proc_string1 = "Hey there, "
proc_code = Proc.new do |n|
puts n + "from a proc storing into a variable!"
end
proc_string1.perform proc_code
#===proc: calling like a block====
proc_string2 = "Hey there, "
proc_string2.perform( Proc.new do |n|
puts n + "from a proc calling like a block!"
end)
#=== Result ===
Hey there, from a proc storing into a variable!
Hey there, from a proc calling like a block!
view raw proc.rb hosted with ❤ by GitHub
3. Lambda
class String
def perform code
code.call(self)
end
end
#===lambda method====
lambda_string = "Hey there, "
lambda_code = lambda do |n|
puts n + "from a lambda!"
end
lambda_string.perform lambda_code
#=== Result ===
Hey there, from a lambda!
view raw lambda.rb hosted with ❤ by GitHub
4. method(:some_method)
class String
def perform code
code.call(self)
end
end
#=== method ====
method_string = "Hey there, "
def func n
puts n + "from a method!"
end
method_string.perform method(:func)
#=== Result ===
Hey there, from a lambda!
view raw method.rb hosted with ❤ by GitHub


Discussion on the subtle differences:
The table below summarizes what each of them can and cannot do, under the table, there are a more in depth explanation on the things shown in the table.
Description Block Proc Lambda Method Proof
Storing into a variable No Yes Yes Yes See (a)
How they work N/A Code Replacement Method Call Method Call See (b)
What class they belong to Proc Proc Proc Method See (c)
Check for correct number of argument No No Yes Yes See (d)

(a) Storing into a variable
Only block is not able to be stored into a variable, the rest is possible, refer to the quick syntax section above.

(b) How they work
def proc_return
Proc.new { return "proc1"}.call
return "proc2 I AM HERE!"
end
def lambda_return
lambda { return "lambda1" }.call
return "lambda2 I AM HERE!"
end
def method_return
method(:func).call
return "method2 I AM HERE!"
end
def func
return "method1"
end
puts proc_return
puts lambda_return
puts method_return
#=== Result ===
proc1
lambda2 I AM HERE!
method2 I AM HERE!
Referring to the code right above this sentence, we can see that for proc_return, the line return "proc2 I AM HERE!" is never executed, this is because, Proc.new{return "proc1}.call works like code replacement, we can imagine proc_return to be like this:
def proc_return
return "proc1"
return "proc2 I AM HERE!"
end

(c) What class they belong to
Run this code:
def what_class(&code)
return code.class
end
def func
"nothing"
end
puts (what_class do end)
puts Proc.new {}.class
puts lambda{}.class
puts method(:func).class
#=== Result ===
Proc
Proc
Proc
Method
view raw what-class.rb hosted with ❤ by GitHub
(d) Check for correct number of argument
Block and Proc don't check for the correct number of arguments, they discard extra parameters silently.(http://www.ruby-doc.org/core-1.9.3/Proc.html#method-i-call). For lambda and method(:func), they give error right away. Here's the code
For block:
def argument_check_correct(&code)
code.call("a1","a2")
end
def argument_check_wrong(&code)
code.call("a1")
end
argument_check_correct do |a1,a2|
puts "block: arguments received: #{a1}, #{a2.class}"
end
argument_check_wrong do |a1,a2|
puts "block: arguments received: #{a1}, #{a2.class}"
end
#====== result =========
block: arguments received: a1, String
block: arguments received: a1, NilClass
view raw block2.rb hosted with ❤ by GitHub
For proc:
def argument_check_correct(code)
code.call("a1","a2")
end
def argument_check_wrong(code)
code.call("a1")
end
proc1 = Proc.new{|a1,a2| puts "proc: arguments received: #{a1}, #{a2.class}"}
argument_check_correct proc1
argument_check_wrong proc1
#====== result =========
proc: arguments received: a1, String
proc: arguments received: a1, NilClass
view raw proc2.rb hosted with ❤ by GitHub
For lambda:
def argument_check_correct(code)
code.call("a1","a2")
end
def argument_check_wrong(code)
code.call("a1")
end
lambda1 = lambda {|a1,a2| puts "proc: arguments received: #{a1}, #{a2.class}"}
argument_check_correct lambda1
argument_check_wrong lambda1
#====== result =========
/Users/tanjunrong/OnlineU/SaaS/Assignments/TestSpace/arg_check_lambda.rb:9: wrong number of arguments (1 for 2) (ArgumentError)
from /Users/tanjunrong/OnlineU/SaaS/Assignments/TestSpace/arg_check_lambda.rb:6:in `call'
from /Users/tanjunrong/OnlineU/SaaS/Assignments/TestSpace/arg_check_lambda.rb:6:in `argument_check_wrong'
from /Users/tanjunrong/OnlineU/SaaS/Assignments/TestSpace/arg_check_lambda.rb:11
proc: arguments received: a1, String
view raw lambda2.rb hosted with ❤ by GitHub
For method(:func):
def argument_check_correct(code)
code.call("a1","a2")
end
def argument_check_wrong(code)
code.call("a1")
end
def func (a1,a2)
puts "method(:func): arguments received: #{a1}, #{a2.class}"
end
argument_check_correct method(:func)
argument_check_wrong method(:func)
#====== result =========
/Users/tanjunrong/OnlineU/SaaS/Assignments/TestSpace/arg_check_method.rb:6:in `func': wrong number of arguments (1 for 2) (ArgumentError)
from /Users/tanjunrong/OnlineU/SaaS/Assignments/TestSpace/arg_check_method.rb:6:in `call'
from /Users/tanjunrong/OnlineU/SaaS/Assignments/TestSpace/arg_check_method.rb:6:in `argument_check_wrong'
from /Users/tanjunrong/OnlineU/SaaS/Assignments/TestSpace/arg_check_method.rb:14
method(:func): arguments received: a1, String
view raw method2.rb hosted with ❤ by GitHub

0 comments: