Ruby: kind_of? vs. instance_of? vs. is_a?
RubyInheritanceIntrospectionRuby Problem Overview
What is the difference? When should I use which? Why are there so many of them?
Ruby Solutions
Solution 1 - Ruby
kind_of?
and is_a?
are synonymous.
instance_of?
is different from the other two in that it only returns true
if the object is an instance of that exact class, not a subclass.
Example:
"hello".is_a? Object
and"hello".kind_of? Object
returntrue
because"hello"
is aString
andString
is a subclass ofObject
.- However
"hello".instance_of? Object
returnsfalse
.
Solution 2 - Ruby
> What is the difference?
From the documentation:
>
- - (Boolean)
instance_of?(class)
- Returns
true
ifobj
is an instance of the given class.
and:
>
- - (Boolean)
is_a?(class)
- (Boolean)kind_of?(class)
- Returns
true
ifclass
is the class ofobj
, or ifclass
is one of the superclasses ofobj
or modules included inobj
.
If that is unclear, it would be nice to know what exactly is unclear, so that the documentation can be improved.
> When should I use which?
Never. Use polymorphism instead.
> Why are there so many of them?
I wouldn't call two "many". There are two of them, because they do two different things.
Solution 3 - Ruby
It is more Ruby-like to ask objects whether they respond to a method you need or not, using respond_to?
. This allows both minimal interface and implementation unaware programming.
It is not always applicable of course, thus there is still a possibility to ask about more conservative understanding of "type", which is class or a base class, using the methods you're asking about.
Solution 4 - Ruby
I also wouldn't call two many (is_a?
and kind_of?
are aliases of the same method), but if you want to see more possibilities, turn your attention to #class
method:
A = Class.new
B = Class.new A
a, b = A.new, B.new
b.class < A # true - means that b.class is a subclass of A
a.class < B # false - means that a.class is not a subclass of A
# Another possibility: Use #ancestors
b.class.ancestors.include? A # true - means that b.class has A among its ancestors
a.class.ancestors.include? B # false - means that B is not an ancestor of a.class
Solution 5 - Ruby
https://stackoverflow.com/a/3893305/10392483 is a great explanation ... to add some more colour to this, I tend to use is_a?
for "primatives" (String, Array, maybe Hash, etc.)
So "hello".is_a?(String)
, [].is_a?(Array)
, {}.is_a?(Hash)
For anything else, I tend to use instance_of? (Animal.new.instance_of?(Animal)
I say tend to because it's not quite that clear cut. Take for example:
class Animal;end
class Dog < Animal;end
x = Dog.new
x.is_a?(Dog) # => true
x.is_a?(Animal) # => true
x.instance_of?(Dog) # => true
x.instance_of?(Animal) # => false
As you can see, x is both a Dog and an Animal, but it's only an instance of Dog.
I see it as a question of specificity:
- If I just want to know that it's an
Animal
and not aPlant
I'll useis_a?
- If I care that it's a
Dog
and not aCat
I'll useinstance_of?
You can then take this further. If I care that it's a Sighthound
and not a Bloodhound
, assuming both are subclasses of Dog
. Then I may want to make it even more specific.
That said, is_a?(Animal|Dog|Sighthound)
will always work. But if you care about the specific subclass, instance_of?
is always more specific.