29

This code works as expected (does nothing, even doesn't produce warning/errors):

l = lambda {|i|}
l.call(1)

This code produces warning (warning: multiple values for a block parameter (0 for 1)):

l = lambda {|i|}
l.call

And this code fails with error (ArgumentError: wrong number of arguments (0 for 2)):

l = lambda {|i, y|}
l.call

I thought that lambda requires all argument to be passed.

And from the second example I see that it isn't. Why does it work when only one argument is given, and works as expected (fails with error) with more than one argument?

PS: ruby 1.8.6 (2008-08-11 patchlevel 287) [universal-darwin9.0]

UPDATE: I've checked these samples with ruby 1.9.1p376. And it works as expected - the second example also produces an error. Looks like this is a feature of 1.8 version (or <=1.8)

3 Answers 3

14

This script will teach you everything you need to know about closures in Ruby.

# So, what's the final verdict on those 7 closure-like entities?          
#
#                                                     "return" returns from closure
#                                    True closure?    or declaring context...?         Arity check?
#                                    ---------------  -----------------------------    -------------------
# 1. block (called with yield)       N                declaring                        no
# 2. block (&b => f(&b) => yield)    N                declaring                        no
# 3. block (&b => b.call)            Y except return  declaring                        warn on too few
# 4. Proc.new                        Y except return  declaring                        warn on too few
# 5. proc                                    <<< alias for lambda in 1.8, Proc.new in 1.9 >>>
# 6. lambda                          Y                closure                          yes, except arity 1
# 7. method                          Y                closure                          yes
Sign up to request clarification or add additional context in comments.

3 Comments

Sorry, but I can't find an answer there. Could you please point?
Thank you! But anyway, it is still unclear why such behaviour exists (to be correct - existed)
@AndersD This behavior existed because there wasn't a "ruby spec" for a really long time, so a lot of it may have been accidentally-emerging behavior. The creation of rubinius led to the creation of a ruby spec, which led to a discovery of such behavior which violated the principle of least surprise. Much work now is going into making sure that behavior that does not need to be different is not different. HTH.
13

Lambdas are weird like that, their behavior is different when you have less than two arguments. Check this article for more information.

Comments

13

When a lambda expects arguments and we don't provide them, or we provide the wrong number of arguments, an exception is thrown.

l = lambda { |name| puts "Today we will practice #{name} meditation." }
l.call
ArgumentError: wrong number of arguments (given 0, expected 1)

We can use the arity method to find out the number of expected arguments:

l.arity  # Output: => 1

Just like methods, lambdas accept all of the following types of parameters/arguments:

  • Positional parameters (required and optional)
  • Single splat parameter (*);
  • Keyword parameters (required and optional);
  • Double splat parameter (**);
  • Explicit block parameter prefixed with ampersand (&).

The following examples illustrate the syntax of a lambda that takes multiple types of arguments.

# Stabby syntax
l = -> (cushion, meditation="kinhin", *room_items, time:, posture: "kekkafuza", **periods, &p) do
  p.call
end

# Regular syntax
l = lambda do |cushion, meditation="kinhin", *room_items, time:, posture:     "kekkafuza", **periods, &p|
  p.call
end

l.call("zafu", "zazen", "zabuton", "incense", time: 40, period1: "morning", period2: "afternoon" ) { puts "Hello from inside the block, which is now a proc." }

Output:
Hello from inside the block, which is now a proc.

Lambdas handle arguments the same way as methods. There is a comprehensive explanation of all the above parameter/argument types in this blog post about methods.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.