'respond_to?' versus 'defined?'
My short answer is I would say either. However, Module#method_defined?
perhaps does not fit in most cases.
It depends on exactly what you want to know. Here is a long answer, explaining the purposes.
I guess the most popular purpose is for Duck-typing,
namely to check whether an object responds to the method with a certain name, and if it does, then you don't care what class of the object it actually is or where/how the method is implemented internally. In this case, Object#respond_to?
is the exact method that is (I think) designed for it (as the method name suggests). It is true (as @Jörg W Mittag pointed out) that the result could be altered if Object#respond_to_missing? is redefined in its class. However, that is the whole purpose of respond_to_missing?
— to register methods as valid — see, for example, the (old) blog post "Method_missing, Politely" by a Ruby core developer Marc-André for clarification.
Another and the traditional way (since Ruby 1) is to use Ruby built-in defined?
. This past answer to "In Ruby, how do I check if method “foo=()” is defined?" explains a potentially useful case specific with defined?
, namely telling whether it is assignment. For the purpose of checking whether a method exists, defined?
works similar to Object#respond_to?
in most (or all?) cases, except it returns a String object or nil as opposed to Boolean. I'd say it is up to personal preference; however, I am in favour of Object#respond_to?
in genearal as it is clearly more specific and hence is readable, and a potential trouble of actual typing, like forgetting a pair of parentheses for defined?
, is more unlikely.
Alternatively, to check whether the class of the object has the method explicity defined with its name in one of itself, its superclasses and included modules, use Module#method_defined?. Specifically, this method ignores respond_to_missing?
, which means in practice any meta programming with BasicObject#method_missing (which ActiveRecord of Rails uses extensively, for example) is disregarded.
Also, as of Ruby 2.6.5, this Module#method_defined?
ignores refinements, that is, the module methods introduced by using
are regarded not defined, in contrast of Object#respond_to?
and built-in defined?
, both of which regards those refine-d methods as defined.
A more primitive(?) way is to use Object#methods like obj.methods.include?(:bar)
to check public and protected methods. An advantage of this way is, you can exclude the methods in the modules included in the class of the object, by specifying the argument true, like obj.methods(false).include?(:bar)
. Also, you can make a finer distinguishment with Object#private_methods
, Object#protected_methods
, Object#public_method
instead, if need be. They all take into account Object#respond_to_missing?.
One more comment re private methods, which include built-in functions (aka Kernel methods).
Object#respond_to? does not respond to a private method in default, unless the second argument is given true (see the past question "How to check if private method is defined in ruby"). For that purpose, use either self.respond_to?(:bar, true)
or Module#private_method_defined? like self.class.private_method_defined?(:bar)
, depending on exactly what you want to check.
To summarise, to check the method called bar
(), do
obj.respond_to?(:bar)
(Object#respond_to?) for duck-typing checkdefined?(obj.bar)
(Built-in `defined?) for general purposesobj.class.method_defined?(:bar)
(Module#method_defined?) for literal definition check, excluding refinementsobj.methods(true).include?(:bar)
(Object#methods) to get the method list and evaluate (where you can exclude the included modules by specifying false)
If I want to check whether a method with a given name is defined, which is better to use,
respond_to?
, ordefined?
?
Neither. Use Module#method_defined?
It's not really a question which is "better" to use: neither the Object#respond_to?
method nor the defined?
unary prefix operator (despite the name!) checks whether the method is defined: they both check whether the receiver responds to a message, which is a completely different thing.
Only Module#method_defined?
will actually check whether the method is defined:
class Foo
def method_missing(*) end
def respond_to_missing?(*) true end
end
foo = Foo.new
defined? foo.bar
#=> 'method'
foo.respond_to?(:bar)
#=> true
Foo.method_defined?(:bar)
#=> false