Labs ICT
โญ Pro Login

Inheritance

Building on existing classes.

Inheritance

Inheritance lets you build new classes on top of existing ones. A child class inherits all the methods and behavior of its parent, and can add or override what it needs. Ruby uses single inheritance โ€” each class has exactly one parent โ€” but combines it with mixins for flexibility.

class Animal
  def speak
    "Some sound"
  end

  def eat(food)
    "Eating #{food}"
  end
end

class Dog < Animal
  def speak
    "Woof!"
  end

  def fetch(item)
    "Fetching #{item}"
  end
end

class Cat < Animal
  def speak
    "Meow!"
  end
end

dog = Dog.new
puts dog.speak      # => "Woof!"
puts dog.eat("bone") # => "Eating bone" (inherited from Animal)
puts dog.fetch("ball") # => "Fetching ball"

cat = Cat.new
puts cat.speak      # => "Meow!"
puts cat.eat("fish") # => "Eating fish"
Try it Yourself ->

Using super

The super keyword calls the parent class's version of the current method. You can call super with no arguments to pass all the original arguments, or pass specific ones.

class Vehicle
  def initialize(make, model)
    @make = make
    @model = model
  end

  def description
    "#{@make} #{@model}"
  end
end

class Car < Vehicle
  def initialize(make, model, doors)
    super(make, model)
    @doors = doors
  end

  def description
    "#{super} (#{@doors}-door)"
  end
end

car = Car.new("Toyota", "Camry", 4)
puts car.description  # => "Toyota Camry (4-door)"
Try it Yourself ->

Method Lookup Chain

When you call a method, Ruby looks it up through the class hierarchy. It starts with the object's class, then moves up to the parent, grandparent, and so on until it finds the method or reaches BasicObject.

class A
  def who_am_i
    "I am A"
  end
end

class B < A
end

class C < B
  def who_am_i
    "I am C"
  end
end

obj = C.new
puts obj.who_am_i  # => "I am C"
puts obj.class.ancestors  # => [C, B, A, Object, Kernel, BasicObject]
Try it Yourself ->

Type Checking: is_a? and kind_of?

You can check whether an object belongs to a certain class or its ancestors using is_a? or its alias kind_of?. These check the entire inheritance chain.

class Shape
end

class Circle < Shape
end

circle = Circle.new

puts circle.is_a?(Circle)   # => true
puts circle.is_a?(Shape)    # => true
puts circle.kind_of?(Shape) # => true (alias for is_a?)
puts circle.class           # => Circle
Try it Yourself ->

Why Single Inheritance?

Ruby deliberately chose single inheritance over multiple inheritance. Multiple inheritance creates the diamond problem โ€” when two parent classes have the same method, which one does the child get? Ruby avoids this by giving you one parent class plus unlimited mixins through modules. You get the simplicity of single inheritance with the flexibility of multiple behaviors. It's the best of both worlds.

module Swimmable
  def swim
    "Swimming!"
  end
end

module Flyable
  def fly
    "Flying!"
  end
end

class Duck < Animal
  include Swimmable
  include Flyable
end

duck = Duck.new
puts duck.speak   # => inherited from Animal
puts duck.swim   # => "Swimming!" (from Swimmable mixin)
puts duck.fly    # => "Flying!" (from Flyable mixin)
Try it Yourself ->

๐Ÿงช Quick Quiz

How do you call a parent method?