Intermediate Ruby - Inheritance, Ancestors

Question Click to View Answer

What does the following code print?

class Mammal
  def warm_blooded?
    true
  end
end

class Dog < Mammal; end

fido = Dog.new
p fido.warm_blooded?
true

The Dog class inherits from the Mammal class so the Dog class has access to all the methods that are defined in the Mammal class.

What does the following code print?

class Mammal
  def self.about
    "we are living creatures with hair"
  end
end

class Dog < Mammal; end

p Dog.about
"we are living creatures with hair"

Class methods are also inherited.

Refactor the following code to not use inheritance.

class Person
  def full_name(first_name, last_name)
    "#{first_name} #{last_name}"
  end
end

class HockeyPlayer < Person
end

player = HockeyPlayer.new
p player.full_name("joe", "sakic")
class Person
  def full_name(first_name, last_name)
    "#{first_name} #{last_name}"
  end
end

class HockeyPlayer
  def full_name(first_name, last_name)
    "#{first_name} #{last_name}"
  end
end

This is terrible because the same code for the full_name() method is repeated in more than one place. The Don't Repeat Yourself (DRY) principle says that code should only be in one place and should never be repeated. Inheritance is one of the main techniques to keep code DRY.

What does the following code print? Explain.

class Dog; end
p Dog.ancestors
[Dog, Object, Kernel, BasicObject]

The Dog class inherits from the Object class and the Object class inherits from the BasicObject class. The Kernel module is mixed-in to the Object class. All user defined classes inherit from the Object class by default. BasicObject is a very simplistic class and is not commonly used. The Kernel module defines methods that are commonly used in Ruby like raise() and puts().

What does the following code print? Explain.

module Purr; end
class Cat
  include Purr
end
p Cat.ancestors
[Cat, Purr, Object, Kernel, BasicObject]

The Cat class inherits from the Object class and the Object class inherits from the BasicObject class. The Cat class mixes in the Purr module and the Object class mixes in the Kernel module.

What does the following code print? Explain.

class Shelter; end
class House < Shelter; end
p House.ancestors
[House, Shelter, Object, Kernel, BasicObject]

The House class inherits from the Shelter class, which inherits from the Object class, which inherits from the BasicObject class. All Ruby objects ultimately inherit from the Object and BasicObject classes that are defined in the core of the Ruby language.

What is the difference between the following two class definitions.

Class Definition #1
class Cat < Object
end

Class Definition #2
class Cat
end

There is no difference between Class Definition #1 and Class Definition #2. Class Definition #1 explicitly inherits from Object, but Class Definition #2 inherits from Object by default (implicitly), so these class definitions are identical.

What does the following code print?

class Parent
  def status
    "I am happy"
  end
end

class Child < Parent
  def status
    "ARGH"
  end
end

p Child.new.status
"ARGH"

The Child class inherits the status method from the Parent class, but overwrites this method. The Child#status method is executed in this example because it overwrote the Parent#status method.

What does the following code print?

class Person
  def initialize(first_name, last_name)
    @first_name = first_name
    @last_name = last_name
  end

  def full_name
    "#{@first_name} #{@last_name}"
  end
end

class Doctor < Person
  def full_name
    "Dr. #{super}"
  end
end

dr_phil = Doctor.new("Phil", "McGraw")
p dr_phil.full_name
"Dr. Phil McGraw"

The Doctor class is initialized with first_name and last_name inputs as it inherits the initialize method from the Person class. The Doctor class overwrites the full_name() method, but uses the super keyword, which calls the Parent#full_name method. In this example, Parent#full_name returns "Phil McGraw" and this return value is concatenated with "Dr." to form the result "Dr. Phil McGraw".

Demonstrate how to create an instance of the Textbook class. Explain.

class Book
  def initialize(args)
    @pages = args.fetch(:pages)
    @title = args.fetch(:title)
  end
end

class Textbook < Book
  def initialize(args)
    @chapters = args.fetch(:chapters)
  end
end
textbook = Textbook.new({ chapters: 20 })

The Textbook class is initialized with a hash that mush contain the key :chapters. The Textbook#initialize method overwrites the Book#initialize method, so a Textbook object does not need to be initialized with a hash containing :pages or :title. initialize() is just like any other method that can be overwritten with inheritance.

Demonstrate how to create an instance of the Saturn class. Explain.

class Planet
  def initialize(mass, volume)
    @mass = mass
    @volume = volume
  end
end

class Saturn < Planet
  def initialize(mass, volume, number_of_rings)
    super(mass, volume)
    @number_of_rings = number_of_rings
  end
end
saturn = Saturn.new(100, 50, 12)

The Saturn class is initialized with mass, volume, and number_of_rings arguments. To set the mass and volume instance variables, the Saturn#initialize method uses super() to call the Planet#initialize method. super() takes mass and volume arguments because the Planet#initialize method requires these two arguments. After calling super() the Saturn#initialize method sets the @number_of_rings instance variable.

Is it appropriate for the Human class to inherit from the Mammal class?

Yes, humans are a type of mammal, so it is appropriate for the Human class to inherit from the Mammal class. The "is a" test is often used to determine if inheritance is reasonable. A human "is a" mammal, so inheritance makes sense.

Is it appropriate for the Board class to inherit from the Game class?

No, a board is not a game, so the "is a" test is not met. When the "is a" test is not met, inheritance should not be used.