Strange behavior with define_method and the wrong number of arguments
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
-
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
-
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) -
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.
-
maybe tell core this
-
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