Categories
Dev Bootcamp

Ruby Classes, Instances and Inheritance

Launch Your Understanding From 0-60 with Ruby Classes

Just as with any object-oriented programming language, class is an important part of Ruby. Everything in Ruby revolves around objects, and all of these objects belong to a class. Unlike in other languages, where each object can have multiple classes, objects in Ruby can only belong to one class. A class is a structure containing similar properties that each instance in the class share, but each instance can have different characteristics for those properties. Arrays, Hashes, and Strings are all examples of classes!

I threw out a lot of terminology, so let me show you an example:

class SuperCar
  def initialize(make, model, year, horsepower, torque)
    @make = make
    @model = model
    @year = year
    @hp = horsepower
    @tq = torque
  end
  def print_specs
    puts "This #{@year} #{@make} #{@model} has #{@hp} horsepower and #{@tq} lb-ft of torque."
  end
end

car_1 = SuperCar.new('Ferrari','458 Italia',2013,570,398)
car_2 = SuperCar.new('Lamborghini','Aventador',2012,691,508)
car_3 = SuperCar.new('McLaren','MP4-12C',2014,616,443)

There are several pieces of code to look at here. We have a class called SuperCar and three instances called car_1, car_2, and car_3. To define a new class, we began by writing the keyword class and then the constant SuperCar. Note that the constant for a class MUST start with a capitalized letter.

The class SuperCar contains the general structure and functions that each instance of this car has. This means that car_1, car_2, and car_3 each has the variables @make, model, @year, @hp, and @tq; and can use the methods initialize and printer_specs. It is important to note that car_1, car_2, and car_3 are not just limited to just these two methods. There are other ways to add new methods to these objects, which are not covered in this post.

Another thing that you see here are instance variables. They are the “properties” of the class, and each instance of the class has a different set of instance variables (i.e. car_1’s @make is Ferrari while car_2’s @make is Lamborghini). Instance variables can be used anywhere within the instance of the class. In the example, the initialize method stores the 5 parameters from initializing a new SuperCar into 5 instance variable assignments. These instance variables can be used in the print_spec method, as well as any other method you decide to create from within the class.

You’d call an instance method that you’ve created in the new class with the . notation, the same way you’d call an instance method from the built-in classes, such as Integers, Arrays, and Hashes. Here is an example of an instance method call and what is displayed on the console:

car_1.print_spec
>>"This 2013 Ferrari 458 Italia has 570 horsepower and 398 lb-ft of torque."
ar_2.print_spec
>>"This 2012 Lamborghini Aventador has 691 horsepower and 508 lb-ft of torque."

While an object cannot belong to more than one class, a class can be a descendant of another class. Descendant classes inherit all of the instance methods from the ancestor class, as well as the ancestor of the ancestor class, and so on.

For example, a certain super car collector takes a portion of his super cars to the racetracks:

class TrackCar < SuperCar
  def set_laptime=(time)
    @laptime = time
  end
  def get_laptime
    @laptime
  end
end

car_4 = TrackCar.new('Ferrari','458 Italia Speciale',2014,597,398)

Again, we have several pieces of code to look at here. In the first piece, I created a class called TrackCar and used the < notation to specify that TrackCar is a descendant of the SuperCar class. This class has two methods: set_laptime (this is a setter method) and get_laptime (and this is a getter method). A setter method allows you to set an instance variable to a value and a getter method allows you to get the value of an instance variable.

Notice that the set_laptime method looks a little funky. Ruby allows you to use the = notation in instance methods to make calling it look more reader-friendly and consistent with variable assignment conventions (i.e. car_4.set_laptime = 98 as opposed to car_4.set_laptime(98)). There is another shortcut to write setter and getter methods, using attr_ attributes (to learn more about them, you can start here).

In the last piece of the code, I created an instance of TrackCar called car_4. Now, let’s run several methods:

car_4.print_specs
>>"This 2014 Ferrari 458 Italia Speciale has 597 horsepower and 398 lb-ft of torque."
car_4.set_laptime = 98
puts "This car's fastest lap time is #{car_4.return_laptime} seconds."
>>"This car's fastest lap time is 98 seconds."

Notice that the print_specs method works even though it was not written in the TrackCar class. This is because TrackCar is a descendant of SuperCar. Any instance of the class TrackCar can use methods from its ancestor classes. If you do not specify an ancestor class, it will default to the class Object. Object is a descendant of BasicObject, which is at the top of the Ruby class hierarchy. That means that all Ruby classes eventually go up to Object and then BasicObject.

This is a good place to stop. We’ve talked about classes, instances, instance variables, instance methods, and class inheritance. To summarize it all, as tutorialspoint puts it, “A class is essentially a blueprint from which individual objects are created.”

This blog has been initially published on tonymai.github.io.

Leave a Reply

Your email address will not be published. Required fields are marked *