Ruby: kind_of? vs. instance_of? vs. is_a?

RubyInheritanceIntrospection

Ruby 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 return true because "hello" is a String and String is a subclass of Object.
  • However "hello".instance_of? Object returns false.

Solution 2 - Ruby

> What is the difference?

From the documentation:

>

- (Boolean) instance_of?(class)
Returns true if obj is an instance of the given class.

and:

>

- (Boolean) is_a?(class)
- (Boolean) kind_of?(class)
Returns true if class is the class of obj, or if class is one of the superclasses of obj or modules included in obj.

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 a Plant I'll use is_a?
  • If I care that it's a Dog and not a Cat I'll use instance_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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionClaudiuView Question on Stackoverflow
Solution 1 - Rubysepp2kView Answer on Stackoverflow
Solution 2 - RubyJörg W MittagView Answer on Stackoverflow
Solution 3 - RubykuoniratView Answer on Stackoverflow
Solution 4 - RubyBoris StitnickyView Answer on Stackoverflow
Solution 5 - RubyAdam ScottView Answer on Stackoverflow