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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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! |
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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! |
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:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def proc_return | |
return "proc1" | |
return "proc2 I AM HERE!" | |
end |
(c) What class they belong to
Run this code:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
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:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
0 comments:
Post a Comment