Skip to content
AgileLogics
6 min read

Inheritance and super

Prerequisites: Class methods

Inheritance lets one class build on another. The new class (the subclass) gets all the methods of the existing one (the superclass) and can add or change behavior.

Real-world analogy: every car is a vehicle. A Car class can inherit everything general from Vehicle (wheels, a move method) and add what's specific to cars.

Syntax

class Subclass < Superclass
end

Example

class Animal
  attr_reader :name

  def initialize(name)
    @name = name
  end

  def speak
    "..."
  end

  def introduce
    "I'm #{name} and I say #{speak}"
  end
end

class Cat < Animal
  def speak
    "meow"
  end
end

class Dog < Animal
  def initialize(name, tricks)
    super(name)
    @tricks = tricks
  end

  def speak
    "woof"
  end

  def introduce
    super + " and I know #{@tricks.length} tricks"
  end
end

puts Cat.new("Tom").introduce
puts Dog.new("Rex", ["sit", "roll"]).introduce
p Dog.superclass
p Dog.new("Rex", []).is_a?(Animal)

Expected output

I'm Tom and I say meow
I'm Rex and I say woof and I know 2 tricks
Animal
true

Line by line:

  • Cat < Animal makes Cat a subclass. It inherits initialize, name, and introduce, and overrides speak.
  • introduce in Animal calls speak — and gets the subclass's version. That's the key idea of inheritance.
  • super calls the superclass's version of the current method. super(name) passes just name up to Animal#initialize.
  • In Dog#introduce, super returns the parent's string, and the subclass adds to it.

super with no parentheses passes along all the arguments the current method received; super() passes none. That difference matters when the parent's initialize takes fewer arguments.

When to use inheritance

Use it for a true "is a kind of" relationship. For sharing a few abilities between unrelated classes, Ruby's modules (a later lesson) are usually a better fit. Deep inheritance chains quickly become hard to follow.

Common mistakes

  • Overriding initialize in a subclass and forgetting to call super, so the parent's instance variables are never set.
  • Writing super when you meant super(), and getting wrong number of arguments.

Practice

Create a Shape class with an area method returning 0 and a describe method returning "Area: #{area}". Add Square (side length) and Circle (radius) subclasses that override area. Print describe for a square of side 3 and a circle of radius 1 (rounded to two decimals).

Show solution
class Shape
  def area = 0

  def describe = "Area: #{area}"
end

class Square < Shape
  def initialize(side)
    @side = side
  end

  def area = @side * @side
end

class Circle < Shape
  def initialize(radius)
    @radius = radius
  end

  def area = (Math::PI * @radius**2).round(2)
end

puts Square.new(3).describe
puts Circle.new(1).describe
Area: 9
Area: 3.14