I noticed the other day that methods defined using define_method have very strange behavior when given the wrong number of arguments. For example, here is a class with a bunch of methods defined using define_method:

class Foo
  define_method :no_args do
    p "no args"
  end
 
  define_method :one_arg do |one|
    p one
  end
 
  define_method :two_args do |one, two|
    p one
    p two
  end
end

Now, if we call no_args with an argument, it will silently ignore the argument:

>> Foo.new.no_args(1)
"no args"
=> nil

However, if we have a method that expects one argument but receives either none or more than one, we get a warning:

>> Foo.new.one_arg
./foo.rb:6: warning: multiple values for a block parameter (0 for 1)
    from (irb):3
nil
=> nil
 
>> Foo.new.one_arg(1,2,3)
./foo.rb:6: warning: multiple values for a block parameter (3 for 1)
    from (irb):2
[1, 2, 3]
=> nil

In the second case, it took all three arguments and passed them as an array into the method expecting one argument.

It gets even stranger with a method that expects two arguments. Now, we actually get errors:

>> Foo.new.two_args
ArgumentError: wrong number of arguments (0 for 2)
    from (irb):2:in 'two_args'
    from (irb):2
 
>> Foo.new.two_args(1,2,3)
ArgumentError: wrong number of arguments (3 for 2)
    from ./foo.rb:10:in 'two_args'
    from (irb):3

I’m not sure why a one argument method gives a warning while a two argument method gives an error. Clearly, define_method is very different from using def.

5 Responses to “Strange behavior with define_method and the wrong number of arguments”

  1. maybe tell core this

  2. It has nothing to do with the behaviuor of the define_method, but it is because you are passing block to define methods and blocks behaves like this in Ruby 1.8.6 but not in 1.8.7

  3. John Hume, thanks for letting me know. I should have said that I did the above using ruby 1.8.6 (2008-03-03 patchlevel 114) [universal-darwin9.0]. I have also seen this behavior with ruby 1.8.5.

  4. Not that this does us any good in the near-term, but define_method methods behave like normal methods with respect to arity in Ruby 1.9.

    
    >> Foo.new.no_args(1)
    ArgumentError: wrong number of arguments (1 for 0)
    >> Foo.new.one_arg
    ArgumentError: wrong number of arguments (0 for 1)
    >> Foo.new.one_arg(1, 2, 3)
    ArgumentError: wrong number of arguments (3 for 1)
    >> Foo.new.two_args
    ArgumentError: wrong number of arguments (0 for 2)
    >> Foo.new.two_args(1, 2, 3)
    ArgumentError: wrong number of arguments (3 for 2)
    
  5. Hi! Your post sparked my interest and I did some research into this. I have attempted to explain this behaviour here: http://code.lemuria-nation.net/?p=108

Sorry, the comment form is closed at this time.

© 2012 Paul Gross's Blog Suffusion theme by Sayontan Sinha