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 ->