Strange behavior with define_method and the wrong number of arguments

written by paul on December 31st, 2008 @ 02:15 PM

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.

Comments

  • Sander Dieleman on 01 Jan 16:42

    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
  • John Hume on 02 Jan 07:54

    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)
    
  • Paul Gross on 02 Jan 15:16

    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.
  • roger on 05 Jan 20:44

    maybe tell core this
  • Selva on 20 May 11:19

    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

Post a comment

Options:

Size

Colors