Difference between various high order functions in Ruby
Hello again~ ❀
In my previous post, different syntax of passing a functions are discussed. Now let's discussed about what the differences they have!
if you haven't read the first post, head over here
Discussion on the subtle differences
Let's have a quick recap of the different methods to pass a function in Ruby:
- block:
do...end
- Proc:
Proc.new do...end
- lambda:
lambda do...end
- method: define a function and pass using
method(:function_name)
(a) Storing into a variable
Let's consider the first criteria. Which of them can be stored into a variable. For example in Proc
's case, it can be stored in a variable like this:
store_proc_in_a_variable.rb
proc = Proc.new do |n|
puts "***" + n + "***"
end
On the other hand, we cannot do that using block
:
block-syntax-error.rb
block = do |n|
puts "***" + n + "***"
end
The above will trigger a syntax error.
Here's a summary on various ways of function, and which can be stored in a variable:
Description | Block | Proc | Lambda | Method |
---|---|---|---|---|
Storing into a variable | No | Yes | Yes | Yes |
Only block
is not able to be stored into a variable, the rest is possible.
(b) How they response to 'return'
Description | Block | Proc | Lambda | Method |
---|---|---|---|---|
How they response to 'return' |
N/A | not scoped | scoped | scoped |
When doing a return in Proc
, it is not scoped to it's own closure, the return
call will actually return out of the parent method. On the other hand, lambda
and method
will be scoped and return in it's own closure. Take a look at the below code and you will understand:
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, because Proc
return out of the parent method.
On the other hand, lambda_return
& method_return
work just like a normal method call, so the second sentence appeared.
(c) What class they belong to
Let's examine what class each of them belong to. By running the code below we can see that all of them came from Proc
except for method
.
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
(d) Check for correct number of argument
Block
and Proc
don’t check for the correct number of arguments, they discard extra parameters silently. For lambda
and method(:func)
, they give error right away. Let's take a look at the code.
For block
shown below, even wrong number of argument is supplied, the output can still be printed.
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
For Proc
, it is the same:
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
For lambda
, we will get a syntax error:
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
arg_check_lambda.rb:9: wrong number of arguments (1 for 2) (ArgumentError)
from arg_check_lambda.rb:6:in `call'
from arg_check_lambda.rb:6:in `argument_check_wrong'
from arg_check_lambda.rb:11
proc: arguments received: a1, String
For method(:func)
, we will also get a syntax error:
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
arg_check_method.rb:6:in `func': wrong number of arguments (1 for 2) (ArgumentError)
from arg_check_method.rb:6:in `call'
from arg_check_method.rb:6:in `argument_check_wrong'
from arg_check_method.rb:14
method(:func): arguments received: a1, String
Summary
By understanding the subtle differences, we can choose the most suitable one to use. I hope this is helpful for you.
Have a nice day~✿~!
Freya Arakaki
Clap to support the author, help others find it, and make your opinion count.