The last topic we will talk about in Object Oriented Programming is the topic of inheritance.
Let's think about the following question. Are police cars and trucks the same?
It's a difficult question, because police cars and trucks are both cars, yet they both have unique features. In this case, we can say that a police car is a car, and a truck is a car.
Let's say we were going to code a Truck
class and a PoliceCar
class. We could define them like this:
class Truck
def speed_up
puts "I'm speeding up!"
end
def speed_down
puts "I'm slowing down!"
end
def print_type
puts "I'm a truck!"
end
end
class PoliceCar
def speed_up
puts "I'm speeding up!"
end
def speed_down
puts "I'm slowing down!"
end
def print_type
puts "I'm a police car!"
end
end
Notice how we have repeating code. We are violating a software engineering principle - DRY, Don't Repeat Yourself. To reduce the repetition, we can create a Car
class, and make the Truck
and Police
classes inherit from Car
.
We can make a class inherit from another class like this:
class Child < Parent
# code here
end
In our car example, we can organize our code like this:
class Car
def speed_up
puts "I'm speeding up!"
end
def speed_down
puts "I'm slowing down!"
end
def print_type
"I'm a car!"
end
end
class Truck < Car
def print_type
puts "I'm a truck!"
end
end
class PoliceCar < Car
def print_type
puts "I'm a police car!"
end
end
Truck.new.speed_up
=> I'm speeding up!
Truck.new.speed_down
=> I'm slowing down!
Truck.new.print_type
=> I'm a truck!
PoliceCar.new.print_type
=> I'm a police car!
PoliceCar.new.speed_up
=> I'm speeding up!
PoliceCar.new.speed_down
=> I'm slowing down!
Notice two things here:
speed_up
and speed_down
inside the child classes (Truck
and PoliceCar
)print_type
method defined in each of the child classes override the print_type
method defined in Car
When a method is called, it first looks into the class that the method was called upon to find the method. If the program finds the method, then the program will return from the method. If it cannot find the method in the class that the method was called upon, then the program will look to the parent class to find the method.
In the example above, the print_type
method is declared inside Truck
and also in Car
. When we call print_type
on an instance of a Truck
class, it finds the print_type
method inside of the Truck
class and returns from the method, preventing the program from running the print_type
method inside of the Car
class.
Now that we've talked about inheritance, let's talk about how all objects in the Ruby language inherit from the BasicObject
class.
Strings, arrays, integers, hashes - everything inherits from BasicObject
. Don't believe me?
Let's open up irb
and see for ourselves. We can use the superclass
method to see the parent class:
String.superclass
The output will show Object
. Then what is the parent class of Object
?
Object.superclass
=> BasicObject
Still don't believe me? Try the same procedure with Array
, Hash
, Integer
, or any other class. Even the Cat
class we created ultimately inherits from BasicObject
.
This means that we actually have access to all of the methods inside the Object
class and the BasicObject
class. You can take a look at all of the methods that all classes have in the documentation.
For example, we can use methods like to_s
or inspect
for any class, because these are methods of Object
.
We can also use methods like new
for every class, since those are methods of BasicObject
. If you're curious, you can take a look at the methods that BasicObject
has here.
In Ruby, we are actually allowed to rewrite the methods inside any of the default Ruby classes such as Object
, String
, Array
, etc. Let's say we want to convert "10"
into an integer with the to_i
method:
"10".to_i
=> 10
The to_i
method is defined inside the String
class. What we can do is rewrite the to_i
method inside the String
class to make it do something else. Open up irb
and type in the following:
class String
def to_i
puts "lol, you can't convert it into an integer now!"
end
end
Now let's try to run "10".to_i
:
"10".to_s
=> lol, you can't convert it into an integer now!
Just like that, we've completely rewritten the Ruby language! (Don't worry, once you exit out of irb
, things will be back to normal).
BasicObject
classBasicObject