skip to content

Type Checks & Duck Typing

Ruby's is_a? and instance_of? check an instance's class, while respond_to? asks what it can do. Interviewers want duck typing preferred, with NoMethodError as its failure mode.

on this pageshow

explore

questions

4

In Ruby, how do is_a?, kind_of? and instance_of? differ when you check an object's class?

level: juniorimportance: must knowfreq 62%

answer

  1. is_a? and kind_of? are aliases
  2. superclasses and included modules count
  3. instance_of? wants the exact class
  4. extended modules count for is_a?
  5. non-class argument: TypeError

basics

~20 s

is_a? and kind_of? are the same method: true when the class is the object's class, a superclass, or a module mixed into it. instance_of? is true only for the object's exact class, so subclasses and modules return false.

solid answer

~40 s

`is_a?` and `kind_of?` are aliases defined by `Kernel` with the same C function. They walk the object's ancestors, so `5.is_a?(Integer)`, `5.is_a?(Numeric)` and `5.is_a?(Comparable)` are all `true`, and a module added to one object with `extend` counts too. `instance_of?` compares the exact class: `5.instance_of?(Integer)` is `true` but `5.instance_of?(Numeric)` is `false`, and it is always `false` for a module. Both raise `TypeError` ("class or module required") when given something that is not a class or module. RuboCop's `Style/ClassCheck` makes a codebase pick one of `is_a?` or `kind_of?`, and `Style/ClassEqualityComparison` flags `obj.class == Foo` in favour of `instance_of?`. In practice `is_a?` is the usual choice, because `instance_of?` rejects subclasses that should be accepted.

code

ruby · 13 lines
ruby
5.is_a?(Integer)         # => true
5.kind_of?(Numeric)      # => true, same method as is_a?
5.is_a?(Comparable)      # => true, module included in Integer's ancestry
5.instance_of?(Integer)  # => true
5.instance_of?(Numeric)  # => false, exact class only

module Exportable; end
row = Object.new
row.extend(Exportable)
row.is_a?(Exportable)    # => true, extend counts
row.instance_of?(Object) # => true

5.is_a?("Integer")       # TypeError: class or module required

go deeper

for a junior

Recall that is_a? and kind_of? are the same and accept superclasses and modules, while instance_of? needs the exact class.

for a middle

Explain that is_a? walks the ancestors, including extended modules, and why instance_of? is always false for a module or a parent class.

for a senior

Justify is_a? over instance_of? when a check is needed, and know which RuboCop cops keep class checks consistent in a codebase.

for a principal

Decide where a codebase allows class checks at all, and how that interacts with proxies, decorators and subclassing in shared libraries.

## Two questions you can ask about an object's class Ruby gives every object three predicate methods from `Kernel` for asking about its class: - **`is_a?(mod)`** and **`kind_of?(mod)`**: two names for one method. "Is this object an instance of `mod`, or of something that inherits from or mixes in `mod`?" - **`instance_of?(klass)`**: "Is this object's class exactly `klass`?" Both kinds take a class or a module and return `true` or `false`. ## What is_a? looks at `is_a?` searches the object's **ancestors**: 1. the object's own class; 2. every superclass up to `BasicObject`; 3. every module included or prepended into any of those classes; 4. modules added to this one object with `extend`, because the search starts from the object's singleton class when it has one. So for `5`: `is_a?(Integer)`, `is_a?(Numeric)`, `is_a?(Comparable)`, `is_a?(Object)` and `is_a?(Kernel)` are all `true`. The Ruby documentation's example uses a class `B < A` where `A` includes a module `M`: a `B` instance is `is_a?` `A`, `B` and `M`, but not `C` (a subclass of `B`). ## What instance_of? looks at `instance_of?` ignores ancestry completely. It compares the object's class (ignoring any singleton class) with the argument: | Expression | `is_a?` | `instance_of?` | |---|---|---| | `5` vs `Integer` | `true` | `true` | | `5` vs `Numeric` | `true` | `false` | | `5` vs `Comparable` (a module) | `true` | `false` | | `Set[1]` vs `Enumerable` | `true` | `false` | | `B.new` vs `A`, where `B < A` | `true` | `false` | Because a module is never an object's class, `instance_of?` with a module is always `false`. ## Errors and edge cases - Passing something that is not a class or module, such as a String naming a class, raises **`TypeError`** with the message `class or module required`. - `obj.class == Foo` behaves like `instance_of?` but reads worse; RuboCop's **`Style/ClassEqualityComparison`** cop flags it and suggests `instance_of?` (it allows the pattern inside `==`, `equal?` and `eql?` definitions by default). - RuboCop's **`Style/ClassCheck`** cop enforces one spelling across a codebase, `is_a?` by default. ## Which one to use - **`is_a?`** is the normal choice when a class check is justified. It accepts subclasses, which is what the Liskov-style contract of inheritance promises callers. - **`instance_of?`** is for the rare case where a subclass must be treated differently from its parent, for example an exact-type check in serialization code. - **Neither** is the first choice in everyday Ruby. Most methods should call the method they need and let any object that implements it through; class checks reject objects such as proxies, decorators and custom collections that would have worked. ## Common mistakes - Believing `kind_of?` is looser or stricter than `is_a?`. They are the same method under two names. - Using `instance_of?(Numeric)` to accept numbers: it rejects every Integer and Float, because their classes are subclasses of `Numeric`. - Checking `is_a?(Array)` to accept "a collection": it rejects `Set`, `Enumerator`, `Hash` and any custom class with `each`, which is exactly where the duck-typing discussion starts. ## In an interview A strong answer states the two rules, gives one example of each diverging (`5.is_a?(Numeric)` true, `5.instance_of?(Numeric)` false), and then adds the judgement: both checks couple code to class names, so idiomatic Ruby reaches for them only when calling the needed method directly is not enough. Mentioning that `kind_of?` is just another spelling of `is_a?` and that `extend` affects `is_a?` shows you know the mechanics, not only the vocabulary. ## A quick mental model Think of `is_a?` as "does this class or module appear anywhere in the object's family tree" and `instance_of?` as "is this the name on the object's own birth certificate". The tree includes mixed-in modules; the certificate never does.

  • Does a module added with `extend` make `is_a?` return true, and does it affect `instance_of?`?
    `is_a?` returns true, because the search starts from the object's singleton class, whose ancestors include the extended module. `instance_of?` is unaffected: it compares the object's real class, skipping the singleton class, and a module can never be that class.
  • Why does RuboCop prefer `instance_of?` over `obj.class == Foo`?
    They test the same thing, exact class identity, but `instance_of?` states the intent directly. `Style/ClassEqualityComparison` flags the comparison forms, including `obj.class.name == "Foo"`, and by default leaves them alone inside `==`, `equal?` and `eql?` definitions, where comparing classes is the usual idiom.

saying these in an interview costs you the question

  • kind_of? also accepts superclasses while is_a? checks only the exact class.
  • instance_of? returns true for a parent class of the object.
  • is_a? ignores modules, so 5.is_a?(Comparable) is false.
  • instance_of?(Numeric) is a good way to accept any number.
  • Passing a class name String to is_a? works like passing the class.
open as a page

In Ruby, how would you write an export method that accepts anything responding to each, and what happens when a caller passes something else?

level: middleimportance: must knowfreq 58%

basics

~20 s

Call rows.each without a class check, so Arrays, Sets, Hashes, Enumerators and any object defining each all work. Anything else fails with NoMethodError, such as undefined method 'each' for an instance of Integer, or for nil.

open as a page

In Ruby, when is checking respond_to? before calling a method the right move, and what can respond_to? get wrong?

level: middleimportance: should knowfreq 45%

basics

~20 s

Use respond_to? when a capability is optional and you branch on it, like flushing only if an output supports flush. It ignores private and protected methods unless you pass true, and objects using method_missing report false without respond_to_missing?.

open as a page

In Ruby, when is an explicit is_a? check still the right choice over duck typing, and what do class checks break?

level: seniorimportance: should knowfreq 38%

basics

~20 s

Check the class when duck typing cannot tell shapes apart (one Hash vs an Array of rows, both with each), when validating parsed input, or in comparisons with other. Class checks reject proxies, decorators and custom collections that would work.

open as a page