Why doesn't a proc care about the number of arguments? - ruby

def method1(&proc)
proc.call(1,2,3)
end
method1{ |x,y,z,a| puts a}
Doesn't throw any error and outputs nil.
Why doesn't it check for the arguments? What's the logic behind it?

Proc's do no care about validating the right number of arguments but lambda's do...
def method1(&proc)
proc.call(1,2,3)
end
method1 { |x,y,z,a| puts a}
method1 lambda { |x,y,z,a| puts a }
Results in:
lambda.rb:1:in `method1': wrong number of arguments (given 1, expected 0) (ArgumentError)
from lambda.rb:6:in `<main>'
From the ruby docs:
For procs created using lambda or ->() an error is generated if the wrong number of parameters are passed to a Proc with multiple parameters. For procs created using Proc.new or Kernel.proc, extra parameters are silently discarded.

Related

How are these objects different? [duplicate]

And when would you use one rather than the other?
One difference is in the way they handle arguments. Creating a proc using proc {} and Proc.new {} are equivalent. However, using lambda {} gives you a proc that checks the number of arguments passed to it. From ri Kernel#lambda:
Equivalent to Proc.new, except the resulting Proc objects check the number of parameters passed when called.
An example:
p = Proc.new {|a, b| puts a**2+b**2 } # => #<Proc:0x3c7d28#(irb):1>
p.call 1, 2 # => 5
p.call 1 # => NoMethodError: undefined method `**' for nil:NilClass
p.call 1, 2, 3 # => 5
l = lambda {|a, b| puts a**2+b**2 } # => #<Proc:0x15016c#(irb):5 (lambda)>
l.call 1, 2 # => 5
l.call 1 # => ArgumentError: wrong number of arguments (1 for 2)
l.call 1, 2, 3 # => ArgumentError: wrong number of arguments (3 for 2)
In addition, as Ken points out, using return inside a lambda returns the value of that lambda, but using return in a proc returns from the enclosing block.
lambda { return :foo }.call # => :foo
return # => LocalJumpError: unexpected return
Proc.new { return :foo }.call # => LocalJumpError: unexpected return
So for most quick uses they're the same, but if you want automatic strict argument checking (which can also sometimes help with debugging), or if you need to use the return statement to return the value of the proc, use lambda.
The real difference between procs and lambdas has everything to do with control flow keywords. I am talking about return, raise, break, redo, retry etc. – those control words. Let's say you have a return statement in a proc. When you call your proc, it will not only dump you out of it, but will also return from the enclosing method e.g.:
def my_method
puts "before proc"
my_proc = Proc.new do
puts "inside proc"
return
end
my_proc.call
puts "after proc"
end
my_method
shoaib#shoaib-ubuntu-vm:~/tmp$ ruby a.rb
before proc
inside proc
The final puts in the method, was never executed, since when we called our proc, the return within it dumped us out of the method. If, however, we convert our proc to a lambda, we get the following:
def my_method
puts "before proc"
my_proc = lambda do
puts "inside proc"
return
end
my_proc.call
puts "after proc"
end
my_method
shoaib#shoaib-ubuntu-vm:~/tmp$ ruby a.rb
before proc
inside proc
after proc
The return within the lambda only dumps us out of the lambda itself and the enclosing method continues executing. The way control flow keywords are treated within procs and lambdas is the main difference between them
There are only two main differences.
First, a lambda checks the number of arguments passed to it, while a proc does not. This means that a lambda will throw an error if you pass it the wrong number of arguments, whereas a proc will ignore unexpected arguments and assign nil to any that are missing.
Second, when a lambda returns, it passes control back to the calling method; when a proc returns, it does so immediately, without going back to the calling method.
To see how this works, take a look at the code below. Our first method calls a proc; the second calls a lambda.
def batman_ironman_proc
victor = Proc.new { return "Batman will win!" }
victor.call
"Iron Man will win!"
end
puts batman_ironman_proc # prints "Batman will win!"
def batman_ironman_lambda
victor = lambda { return "Batman will win!" }
victor.call
"Iron Man will win!"
end
puts batman_ironman_lambda # prints "Iron Man will win!"
See how the proc says "Batman will win!", this is because it returns immediately, without going back to the batman_ironman_proc method.
Our lambda, however, goes back into the method after being called, so the method returns the last code it evaluates: "Iron Man will win!"
# Proc Examples
p = Proc.new { |x| puts x*2 }
[1,2,3].each(&p) # The '&' tells ruby to turn the proc into a block
proc = Proc.new { puts "Hello World" }
proc.call
# Lambda Examples
lam = lambda { |x| puts x*2 }
[1,2,3].each(&lam)
lam = lambda { puts "Hello World" }
lam.call
Differences between Procs and Lambdas
Before I get into the differences between procs and lambdas, it is important to mention that they are both Proc objects.
proc = Proc.new { puts "Hello world" }
lam = lambda { puts "Hello World" }
proc.class # returns 'Proc'
lam.class # returns 'Proc'
However, lambdas are a different ‘flavor’ of procs. This slight difference is shown when returning the objects.
proc # returns '#<Proc:0x007f96b1032d30#(irb):75>'
lam # returns '<Proc:0x007f96b1b41938#(irb):76 (lambda)>'
1. Lambdas check the number of arguments, while procs do not
lam = lambda { |x| puts x } # creates a lambda that takes 1 argument
lam.call(2) # prints out 2
lam.call # ArgumentError: wrong number of arguments (0 for 1)
lam.call(1,2,3) # ArgumentError: wrong number of arguments (3 for 1)
In contrast, procs don’t care if they are passed the wrong number of arguments.
proc = Proc.new { |x| puts x } # creates a proc that takes 1 argument
proc.call(2) # prints out 2
proc.call # returns nil
proc.call(1,2,3) # prints out 1 and forgets about the extra arguments
2. Lambdas and procs treat the ‘return’ keyword differently
‘return’ inside of a lambda triggers the code right outside of the lambda code
def lambda_test
lam = lambda { return }
lam.call
puts "Hello world"
end
lambda_test # calling lambda_test prints 'Hello World'
‘return’ inside of a proc triggers the code outside of the method where the proc is being executed
def proc_test
proc = Proc.new { return }
proc.call
puts "Hello world"
end
proc_test # calling proc_test prints nothing
And to answer your other query, which one to use and when ? I'll follow #jtbandes as he has mentioned
So for most quick uses they're the same, but if you want automatic
strict argument checking (which can also sometimes help with
debugging), or if you need to use the return statement to return the
value of the proc, use lambda.
Originally posted here
Generally speaking, lambdas are more intuitive than procs because they’re
more similar to methods. They’re pretty strict about arity, and they simply
exit when you call return . For this reason, many Rubyists use lambdas as a
first choice, unless they need the specific features of procs.
Procs: Objects of class Proc . Like blocks, they are evaluated in the scope
where they’re defined.
Lambdas: Also objects of class Proc but subtly different from regular procs.
They’re closures like blocks and procs, and as such they’re evaluated in
the scope where they’re defined.
Creating Proc
a = Proc.new { |x| x 2 }
Creating lambda
b = lambda { |x| x 2 }
Here is another way to understand this.
A block is a chunk of code attached to the invocation to a call of a method on an object. In the below example, self is an instance of an anonymous class inheriting from ActionView::Base in the Rails framework (which itself includes many helper modules). card is a method we call on self. We pass in an argument to the method and then we always attach the block to the end of the method invocation:
self.card :contacts do |c|
// a chunk of valid ruby code
end
Ok, so we are passing a chunk of code to a method. But how do we make use of this block? One option is to convert the chunk of code into an object. Ruby offers three ways to convert a chunk of code into an object
# lambda
> l = lambda { |a| a + 1 }
> l.call(1)
=> 2
# Proc.new
> l2= Proc.new { |a| a + 1 }
> l2.call(1)
=> 2
# & as the last method argument with a local variable name
def add(&block)
end
In the method above, the & converts the block passed to the method into an object and stores that object in the local variable block. In fact, we can show that it has the same behavior as lambda and Proc.new:
def add(&block)
block
end
l3 = add { |a| a + 1 }
l3.call(1)
=> 2
This is IMPORTANT. When you pass a block to a method and convert it using &, the object it creates uses Proc.new to do the conversion.
Note that I avoided the use of "proc" as an option. That's because it Ruby 1.8, it is the same as lambda and in Ruby 1.9, it is the same as Proc.new and in all Ruby versions it should be avoided.
So then you ask what is the difference between lambda and Proc.new?
First, in terms of parameter passing, lambda behaves like a method call. It will raise an exception if you pass the wrong number of arguments. In contrast, Proc.new behaves like parallel assignment. All unused arguments get converted into nil:
> l = lambda {|a,b| puts "#{a} + #{b}" }
=> #<Proc:0x007fbffcb47e40#(irb):19 (lambda)>
> l.call(1)
ArgumentError: wrong number of arguments (1 for 2)
> l2 = Proc.new {|a,b| puts "#{a} + #{b}" }
=> #<Proc:0x007fbffcb261a0#(irb):21>
> l2.call(1)
1 +
Second, lambda and Proc.new handle the return keyword differently. When you do a return inside of Proc.new, it actually returns from the enclosing method, that is, the surrounding context. When you return from a lambda block, it just returns from the block, not the enclosing method. Basically, it exits from the call to the block and continues execution with the rest of the enclosing method.
> def add(a,b)
l = Proc.new { return a + b}
l.call
puts "now exiting method"
end
> add(1,1)
=> 2 # NOTICE it never prints the message "now exiting method"
> def add(a,b)
l = lambda { return a + b }
l.call
puts "now exiting method"
end
> add(1,1)
=> now exiting method # NOTICE this time it prints the message "now exiting method"
So why this behavioral difference? The reason is because with Proc.new, we can use iterators inside the context of enclosing methods and draw logical conclusions. Look at this example:
> def print(max)
[1,2,3,4,5].each do |val|
puts val
return if val > max
end
end
> print(3)
1
2
3
4
We expect that when we invoke return inside the iterator, it will return from the enclosing method. Remember the blocks passed to iterators get converted to objects using Proc.new and that is why when we use return, it will exit the enclosing method.
You can think of lambdas as anonymous methods, they isolate individual blocks of code into an object that can be treated like a method. Ultimately, think of a lambda as behaving as an anomyous method and Proc.new behaving as inline code.
A helpful post on ruby guides: blocks, procs & lambdas
Procs return from the current method, while lambdas return from the lambda itself.
Procs don’t care about the correct number of arguments, while lambdas will raise an exception.
the differences between proc and lambda is that proc is just a copy of code with arguments replaced in turn, while lambda is a function like in other languages. (behavior of return, arguments checks)

How to return a lambda that is returned by another method in Ruby

I tried this, but it does notwork.
def n_times(thing)
lambda {|n| thing * n }
end
def other(counter,thing)
com = counter(thing)
return com
end
com = other(n_times,10)
com.call("what ")
error :
test.rb:1:in `n_times': wrong number of arguments (0 for 1) (ArgumentError)
from test.rb:10:in `<main>'
n_times is a method requiring one argument, you are calling it as the first argument passed to other, but without an argument. That's the error you are getting. You want to pass method(:n_times) which converts it to a Proc rather than calling it.
Secondly you have counter(thing) inside the other method. This is calling the method called 'counter', rather than using the object called 'counter' which is passed as an argument. You want to change that to counter[thing].
Lastly, you are passing 10 to n_times and calling the resulting lambda with "what", but that evaluates 10 * "what" which is a NoMethodError. You need to reverse those arguments.
All together:
def n_times(thing)
lambda { |n| thing * n }
end
def other(counter, thing)
counter[thing]
end
other(method(:n_times), "what").call(10)
# "whatwhatwhatwhatwhatwhatwhatwhatwhatwhat"

Can someone explain empty parameters in Ruby?

Every time I've seen empty parameters, it appeared in a method like this:
def method_name(arguments)
#stuff to be executed
end
And then a method is called. Now I've come across this:
x = something()
What am I looking at? I am aware it is a variable, but what is the empty part?
Imagine a situation where you have a variable something and a method something. Whenever you refer something() you are referring to the method.
def something
"Java"
end
something = "Ruby"
a = something #=> value of a is "Ruby"
a = something() #=> value of a is "Java" # got from method
Ruby method parameters are very flexible. According to the method definition, the parameters that are given in the call can be passed directly, defaulted if absent, or compressed to a single Array parameter.
This short program demonstrates. The way parameter checking works is
Parameters supplied in the call are first allocated to all the individual non-defaulted parameters in the method definition, from first to last.
If there are insufficient actual parameters to match all non-defaulted formal parameters, a wrong number of arguments (N for M) (ArgumentError) is raised.
If any actual parameters remain then they are then allocated to all defaulted parameters, from first to last.
If any actual parameters still remain, then they will be bundled into an array and allocated to a splat parameter, if one has been defined.
If any actual parameters still remain, and no splat parameters have been defined, a wrong number of arguments (N for M) (ArgumentError) is raised.
This program demonstrates some of those situations. The commented lines would raise the error described.
def method_name(arguments)
puts "method_name(#{arguments})"
end
def something()
puts 'something()'
end
def something_else(param = 99)
puts "something_else(#{param})"
end
def something_more(param = 99, *rest)
puts "something_else(#{param}, #{rest})"
end
#method_name()
method_name(1)
#something(1)
something()
something_else()
something_else(42)
something_more()
something_more(1)
something_more(1, 2)
output
method_name(1)
something()
something_else(99)
something_else(42)
something_more(99, [])
something_more(1, [])
something_more(1, [2])
In ruby, parentheses are optional, so in your example, calling method_name is the equivalent of calling method_name(), however your method requires an argument. Perhaps this would illustrate it better:
def method_name(arguments={})
#do stuff
end
This method has an optional parameter of a hash. You can call this method with any of: method_name, method_name(), or method_name(argument1: "something")

How to pass blocks between methods?

I have two methods which both except a block, however one of the methods needs to pass its block to the other.
def one(&block)
two(block)
end
def two(&block)
block.call
end
In the real code other parameters are passed and one is syntax sugar over two.
I want to be able to call both one and two with a block.
one { } # => okay
two { } # => ArgumentError: wrong number of arguments (1 for 0)
I can see why I get the ArgumentError, two takes no argument as such. I'm not quite sure how to phrase this but &block designates the block appears after the passed in arguments, hence the error.
Ruby 1.9
You could just pass the &block to your second method like so:
def one(&block)
two(&block)
end
def two(&block)
block.call
end
one { puts "Hello World" }
Hello World
#=> nil
Update
You could also do something like this
def one
two(&Proc.new)
end
def two(&block)
block.call
end
It will have the same output as above. Do note that if no block is given to one, it will raise an ArgumentError: tried to create Proc object without a block so you'd have to check if the block is given by calling if block_given?
You could do the same with yield:
def one
two { yield }
end
def two
yield
end

What's the difference between a proc and a lambda in Ruby?

And when would you use one rather than the other?
One difference is in the way they handle arguments. Creating a proc using proc {} and Proc.new {} are equivalent. However, using lambda {} gives you a proc that checks the number of arguments passed to it. From ri Kernel#lambda:
Equivalent to Proc.new, except the resulting Proc objects check the number of parameters passed when called.
An example:
p = Proc.new {|a, b| puts a**2+b**2 } # => #<Proc:0x3c7d28#(irb):1>
p.call 1, 2 # => 5
p.call 1 # => NoMethodError: undefined method `**' for nil:NilClass
p.call 1, 2, 3 # => 5
l = lambda {|a, b| puts a**2+b**2 } # => #<Proc:0x15016c#(irb):5 (lambda)>
l.call 1, 2 # => 5
l.call 1 # => ArgumentError: wrong number of arguments (1 for 2)
l.call 1, 2, 3 # => ArgumentError: wrong number of arguments (3 for 2)
In addition, as Ken points out, using return inside a lambda returns the value of that lambda, but using return in a proc returns from the enclosing block.
lambda { return :foo }.call # => :foo
return # => LocalJumpError: unexpected return
Proc.new { return :foo }.call # => LocalJumpError: unexpected return
So for most quick uses they're the same, but if you want automatic strict argument checking (which can also sometimes help with debugging), or if you need to use the return statement to return the value of the proc, use lambda.
The real difference between procs and lambdas has everything to do with control flow keywords. I am talking about return, raise, break, redo, retry etc. – those control words. Let's say you have a return statement in a proc. When you call your proc, it will not only dump you out of it, but will also return from the enclosing method e.g.:
def my_method
puts "before proc"
my_proc = Proc.new do
puts "inside proc"
return
end
my_proc.call
puts "after proc"
end
my_method
shoaib#shoaib-ubuntu-vm:~/tmp$ ruby a.rb
before proc
inside proc
The final puts in the method, was never executed, since when we called our proc, the return within it dumped us out of the method. If, however, we convert our proc to a lambda, we get the following:
def my_method
puts "before proc"
my_proc = lambda do
puts "inside proc"
return
end
my_proc.call
puts "after proc"
end
my_method
shoaib#shoaib-ubuntu-vm:~/tmp$ ruby a.rb
before proc
inside proc
after proc
The return within the lambda only dumps us out of the lambda itself and the enclosing method continues executing. The way control flow keywords are treated within procs and lambdas is the main difference between them
There are only two main differences.
First, a lambda checks the number of arguments passed to it, while a proc does not. This means that a lambda will throw an error if you pass it the wrong number of arguments, whereas a proc will ignore unexpected arguments and assign nil to any that are missing.
Second, when a lambda returns, it passes control back to the calling method; when a proc returns, it does so immediately, without going back to the calling method.
To see how this works, take a look at the code below. Our first method calls a proc; the second calls a lambda.
def batman_ironman_proc
victor = Proc.new { return "Batman will win!" }
victor.call
"Iron Man will win!"
end
puts batman_ironman_proc # prints "Batman will win!"
def batman_ironman_lambda
victor = lambda { return "Batman will win!" }
victor.call
"Iron Man will win!"
end
puts batman_ironman_lambda # prints "Iron Man will win!"
See how the proc says "Batman will win!", this is because it returns immediately, without going back to the batman_ironman_proc method.
Our lambda, however, goes back into the method after being called, so the method returns the last code it evaluates: "Iron Man will win!"
# Proc Examples
p = Proc.new { |x| puts x*2 }
[1,2,3].each(&p) # The '&' tells ruby to turn the proc into a block
proc = Proc.new { puts "Hello World" }
proc.call
# Lambda Examples
lam = lambda { |x| puts x*2 }
[1,2,3].each(&lam)
lam = lambda { puts "Hello World" }
lam.call
Differences between Procs and Lambdas
Before I get into the differences between procs and lambdas, it is important to mention that they are both Proc objects.
proc = Proc.new { puts "Hello world" }
lam = lambda { puts "Hello World" }
proc.class # returns 'Proc'
lam.class # returns 'Proc'
However, lambdas are a different ‘flavor’ of procs. This slight difference is shown when returning the objects.
proc # returns '#<Proc:0x007f96b1032d30#(irb):75>'
lam # returns '<Proc:0x007f96b1b41938#(irb):76 (lambda)>'
1. Lambdas check the number of arguments, while procs do not
lam = lambda { |x| puts x } # creates a lambda that takes 1 argument
lam.call(2) # prints out 2
lam.call # ArgumentError: wrong number of arguments (0 for 1)
lam.call(1,2,3) # ArgumentError: wrong number of arguments (3 for 1)
In contrast, procs don’t care if they are passed the wrong number of arguments.
proc = Proc.new { |x| puts x } # creates a proc that takes 1 argument
proc.call(2) # prints out 2
proc.call # returns nil
proc.call(1,2,3) # prints out 1 and forgets about the extra arguments
2. Lambdas and procs treat the ‘return’ keyword differently
‘return’ inside of a lambda triggers the code right outside of the lambda code
def lambda_test
lam = lambda { return }
lam.call
puts "Hello world"
end
lambda_test # calling lambda_test prints 'Hello World'
‘return’ inside of a proc triggers the code outside of the method where the proc is being executed
def proc_test
proc = Proc.new { return }
proc.call
puts "Hello world"
end
proc_test # calling proc_test prints nothing
And to answer your other query, which one to use and when ? I'll follow #jtbandes as he has mentioned
So for most quick uses they're the same, but if you want automatic
strict argument checking (which can also sometimes help with
debugging), or if you need to use the return statement to return the
value of the proc, use lambda.
Originally posted here
Generally speaking, lambdas are more intuitive than procs because they’re
more similar to methods. They’re pretty strict about arity, and they simply
exit when you call return . For this reason, many Rubyists use lambdas as a
first choice, unless they need the specific features of procs.
Procs: Objects of class Proc . Like blocks, they are evaluated in the scope
where they’re defined.
Lambdas: Also objects of class Proc but subtly different from regular procs.
They’re closures like blocks and procs, and as such they’re evaluated in
the scope where they’re defined.
Creating Proc
a = Proc.new { |x| x 2 }
Creating lambda
b = lambda { |x| x 2 }
Here is another way to understand this.
A block is a chunk of code attached to the invocation to a call of a method on an object. In the below example, self is an instance of an anonymous class inheriting from ActionView::Base in the Rails framework (which itself includes many helper modules). card is a method we call on self. We pass in an argument to the method and then we always attach the block to the end of the method invocation:
self.card :contacts do |c|
// a chunk of valid ruby code
end
Ok, so we are passing a chunk of code to a method. But how do we make use of this block? One option is to convert the chunk of code into an object. Ruby offers three ways to convert a chunk of code into an object
# lambda
> l = lambda { |a| a + 1 }
> l.call(1)
=> 2
# Proc.new
> l2= Proc.new { |a| a + 1 }
> l2.call(1)
=> 2
# & as the last method argument with a local variable name
def add(&block)
end
In the method above, the & converts the block passed to the method into an object and stores that object in the local variable block. In fact, we can show that it has the same behavior as lambda and Proc.new:
def add(&block)
block
end
l3 = add { |a| a + 1 }
l3.call(1)
=> 2
This is IMPORTANT. When you pass a block to a method and convert it using &, the object it creates uses Proc.new to do the conversion.
Note that I avoided the use of "proc" as an option. That's because it Ruby 1.8, it is the same as lambda and in Ruby 1.9, it is the same as Proc.new and in all Ruby versions it should be avoided.
So then you ask what is the difference between lambda and Proc.new?
First, in terms of parameter passing, lambda behaves like a method call. It will raise an exception if you pass the wrong number of arguments. In contrast, Proc.new behaves like parallel assignment. All unused arguments get converted into nil:
> l = lambda {|a,b| puts "#{a} + #{b}" }
=> #<Proc:0x007fbffcb47e40#(irb):19 (lambda)>
> l.call(1)
ArgumentError: wrong number of arguments (1 for 2)
> l2 = Proc.new {|a,b| puts "#{a} + #{b}" }
=> #<Proc:0x007fbffcb261a0#(irb):21>
> l2.call(1)
1 +
Second, lambda and Proc.new handle the return keyword differently. When you do a return inside of Proc.new, it actually returns from the enclosing method, that is, the surrounding context. When you return from a lambda block, it just returns from the block, not the enclosing method. Basically, it exits from the call to the block and continues execution with the rest of the enclosing method.
> def add(a,b)
l = Proc.new { return a + b}
l.call
puts "now exiting method"
end
> add(1,1)
=> 2 # NOTICE it never prints the message "now exiting method"
> def add(a,b)
l = lambda { return a + b }
l.call
puts "now exiting method"
end
> add(1,1)
=> now exiting method # NOTICE this time it prints the message "now exiting method"
So why this behavioral difference? The reason is because with Proc.new, we can use iterators inside the context of enclosing methods and draw logical conclusions. Look at this example:
> def print(max)
[1,2,3,4,5].each do |val|
puts val
return if val > max
end
end
> print(3)
1
2
3
4
We expect that when we invoke return inside the iterator, it will return from the enclosing method. Remember the blocks passed to iterators get converted to objects using Proc.new and that is why when we use return, it will exit the enclosing method.
You can think of lambdas as anonymous methods, they isolate individual blocks of code into an object that can be treated like a method. Ultimately, think of a lambda as behaving as an anomyous method and Proc.new behaving as inline code.
A helpful post on ruby guides: blocks, procs & lambdas
Procs return from the current method, while lambdas return from the lambda itself.
Procs don’t care about the correct number of arguments, while lambdas will raise an exception.
the differences between proc and lambda is that proc is just a copy of code with arguments replaced in turn, while lambda is a function like in other languages. (behavior of return, arguments checks)

Resources