Ruby 3.1 adds Class#descendants


We often land on a situation where we want to know all the classes which have been inherited from a given class; One such scenario can be while using Single Table Inheritance in Rails.

Here, we might want to identify those classes that are derived from a class.

Rails ~> 3.0 already has such a feature provided by ActiveSupport Class#descendants.

To cater to such requirements in Ruby, Ruby 3.1 introduced Class#descendants that returns an array of classes directly or indirectly inheriting from the receiver, without including the receiver or singleton classes.

Before

We can implement Class#descendants using the code snippet given below-

  class Animal
    def self.descendants
      ObjectSpace.each_object(Class).select { |klass| klass < self }
    end
  end

  class Mammal < Animal; end
  class Dolphin < Mammal; end
  class Bat < Mammal; end

  class Reptile < Animal; end
  class Crocodile < Reptile; end

  Animal.descendants
  => [Reptile, Bat, Crocodile, Dolphin, Mammal]

  Mammal.descendants
  => [Bat, Dolphin]

  Reptile.descendants
  => [Crocodile]

After

  class Animal; end

  class Mammal < Animal; end
  class Dolphin < Mammal; end
  class Bat < Mammal; end

  class Reptile < Animal; end
  class Crocodile < Reptile; end

  Animal.descendants
  => [Reptile, Crocodile, Mammal, Bat, Dolphin]

  Mammal.descendants
  => [Bat, Dolphin]

  Reptile.descendants
  => [Crocodile]

For more discussion related to this change, please refer to this PR.

Join Our Newsletter