Lesson 4
Inheritance in Ruby: Exploring Attributes and Methods
Introduction

Welcome back! In this part of our Ruby Class Basics Review, we’ll dive into inheritance, a core concept in Ruby’s object-oriented programming (OOP). Inheritance enables code-sharing between classes, making our code more efficient and easier to read.

This lesson covers how inheritance works in Ruby, including attribute and method inheritance, along with the super keyword to access superclass functionality. Ready to dive in? Let’s get started!

Defining Inheritance

Inheritance in Ruby allows us to create a subclass that inherits attributes and methods from a superclass. This approach is especially useful when multiple classes share common features or behaviors.

Let’s explore with a superclass named Vehicle and a subclass named Car:

Ruby
1# Define the superclass 'Vehicle' 2class Vehicle 3 # Initialize the Vehicle with color and brand attributes 4 def initialize(color, brand) 5 @color = color 6 @brand = brand 7 end 8end 9 10# Define the subclass 'Car', inheriting from 'Vehicle' 11class Car < Vehicle 12 def initialize(color, brand, doors) 13 # Use 'super' to call the superclass's initialize method 14 super(color, brand) 15 @doors = doors 16 end 17end

In this example, Car inherits properties from Vehicle. Ruby supports several types of inheritance, but here we’re focusing on single inheritance, where a subclass has a single superclass.

Attribute Inheritance with attr_reader

With attribute inheritance, a subclass can inherit instance variables from its superclass.

Ruby
1class Artist 2 attr_reader :name # Getter for @name 3 4 def initialize(name) 5 @name = name # Superclass's attribute 6 end 7end 8 9class Musician < Artist 10 attr_reader :instrument # Getter for @instrument 11 12 def initialize(name, instrument) 13 super(name) # Inheriting superclass's attribute 14 @instrument = instrument # Subclass's own attribute 15 end 16end 17 18john = Musician.new('John Lennon', 'Guitar') 19puts john.name # Output: John Lennon 20puts john.instrument # Output: Guitar

The Musician class inherits the @name attribute from Artist, while also introducing its own attribute, @instrument. Getters can be conveniently defined using attr_reader to access instance variables of each class.

Method Inheritance

Similar to attributes, method inheritance lets a subclass use methods defined in its superclass without redefining them.

In the example below, the Car class inherits the start method from the Vehicle class:

Ruby
1class Vehicle 2 def initialize(brand) 3 @brand = brand 4 end 5 6 def start 7 puts "The #{@brand} is starting." 8 end 9end 10 11class Car < Vehicle 12 # No new methods or attributes added here 13end 14 15my_car = Car.new('BMW') 16my_car.start # Output: The BMW is starting.

In this case, Car can use the start method inherited from Vehicle.

Understanding the `super` Keyword

The super keyword is essential in Ruby inheritance, allowing a subclass to call methods from its superclass. super is especially useful in method overrides or in initialize methods to ensure that superclass functionality is included in the subclass.

Here’s how super can be used to call an overridden method in the superclass and combine it with new behavior in the subclass:

Ruby
1class Vehicle 2 def start 3 "Vehicle is starting..." 4 end 5end 6 7class Car < Vehicle 8 def start 9 "#{super} Beep! Beep!" 10 end 11end 12 13my_car = Car.new 14puts my_car.start # Output: Vehicle is starting... Beep! Beep!

Similarly, in initialize, super allows us to ensure that both superclass and subclass attributes are set up properly:

Ruby
1class ParentClass 2 attr_reader :value # Getter for @value 3 4 def initialize(value) 5 @value = value 6 end 7end 8 9class ChildClass < ParentClass 10 attr_reader :additional_value # Getter for @additional_value 11 12 def initialize(value, additional_value) 13 super(value) # Calls superclass's initialize 14 @additional_value = additional_value 15 end 16end 17 18child = ChildClass.new("value", "additional_value") 19puts child.value # Output: value 20puts child.additional_value # Output: additional_value

In both examples, super allows the subclass to build upon the superclass’s logic, resulting in flexible and reusable code.

Using self.class for Shared Class Methods and Variables

In Ruby, self.class allows instance methods to dynamically call class methods or access shared data. For example, we can track the total number of books checked out in a library system:

Ruby
1class Library 2 @books_checked_out = 0 3 4 class << self 5 # Defines class-level methods for shared behavior 6 attr_reader :books_checked_out 7 8 def checkout_book 9 @books_checked_out ||= 0 # Initialize @books_checked_out if it's nil 10 @books_checked_out += 1 11 end 12 end 13end 14 15class LibraryMember < Library 16 def checkout 17 self.class.checkout_book 18 "A book has been checked out. Total checked out: #{self.class.books_checked_out}" 19 end 20end 21 22member = LibraryMember.new 23puts member.checkout # Output: A book has been checked out. Total checked out: 1 24 25another_member = LibraryMember.new 26puts another_member.checkout # Output: A book has been checked out. Total checked out: 2

In this example:

  • @books_checked_out is a class instance variable, storing data shared among all instances of the Library class.
  • class << self opens the singleton class, allowing us to define class-level methods like books_checked_out and checkout_book in a grouped and organized manner.
  • The checkout method in LibraryMember uses self.class to dynamically call class methods (checkout_book and books_checked_out) on the Library class.

This design ensures shared data is managed centrally while allowing dynamic access and modifications through instance methods.

Lesson Summary

In this lesson, we explored inheritance in Ruby, covering both attribute and method inheritance. We also discussed how the super keyword allows subclasses to access superclass methods for extending or combining behaviors. Practicing inheritance will help you write more efficient, organized, and modular Ruby code. Get ready to apply these concepts in some hands-on exercises to deepen your understanding!

Enjoy this lesson? Now it's time to practice with Cosmo!
Practice is how you turn knowledge into actual skills.