Ruby OOP: Class Inheritance - Women Who Code.
Resources for women who code
women who code, girls who code, ladies who code
52028
post-template-default,single,single-post,postid-52028,single-format-standard,qode-core-1.0.1,ajax_fade,page_not_loaded,,capri child-child-ver-1.0.0,capri-ver-1.6, vertical_menu_with_scroll,smooth_scroll,grid_1200,blog_installed,wpb-js-composer js-comp-ver-4.12.1,vc_responsive
 

Ruby OOP: Class Inheritance

Ruby OOP: Class Inheritance

This is a piece from the Learn Ruby course on Coursera.

Lecture 11: Class Inheritance (8:44 min), from section “OOP in Ruby” of the Coursera’s course “Ruby on Rails: An Introduction”, week 2.
https://www.coursera.org/learn/ruby-on-rails-intro/lecture/lqLgn/class-inheritance

Summary:

  1. The || (double pipe) operator (conditional assignment operator)
  2. Class methods and class variables
  3. Class inheritance

The || (double pipe) operator

So what does || do? It:

  1. first, evaluates the left side
  2. if it’s true – returns it
  3. else – returns the right side

Example:

@x = @x || 5 # returns 5 the 1st time and @x the next time

Short form:

@x ||= 5 # does the same as above

Useful link(s) on conditional assignment operator:
https://www.codecademy.com/en/forum_questions/5149680470d288f3540016f6

Let’s see why this || operator is useful.

Here we have a person, an age getter and the name, getter in the setter. We have a constructor. And we have an age setter method that takes an age. We could say: well, the age is new_age unless it’s greater than 120. But it’d be nice to have some sort of a default. So we’re saying: assign the age variable to itself, which is gonna be nil in the 1st pass because we haven’t created an instance of a Person class yet.

class Person 
  attr_reader :age 
  attr_accessor :name 
  
  def initialize (name, age) # CONSTRUCTOR 
    @name = name 
    self.age = age # call the age= method 
  end 
  def age= (new_age) 
    @age ||= 5 # default: only sets to 5 the 1st time when the valuse is not yet assigned 
    @age = new_age unless new_age > 120 
  end 
end 
person1 = Person.new("Kim", 130) 
puts person1.age # => 5 (default) 
person1.age = 10 # change to 10 
puts person1.age # => 10 
person1.age = 200 # Try to change to 200 
puts person1.age # => 10 (still) 

After the 1st pass, if an age is already set, it will be just using that set value. If it’s not set, is nil or false, the value to the right side will be used (5). Let’s see this in action. We have a person1 object that gets created from a Person class. Let’s try to create the value of 130. Now, 130, obviously is more than 120, so this line is not gonna execute:

@age = new_age unless new_age > 120 

But this line will:

@age ||= 5

Which means that you’re gonna have 5, by the time you get here

Then we try to change it to 10. So what happens is new age, which is 10 is shown. We’re not gonna touch this value, because it already has been assigned to 5. So it’s gonna say, okay, age is age of 5, and age already is not nil, not false, so this 5 gets ignored, but then it gets assigned to 10. And then after that, we try to change it to 200, and again, it’s assigned to 10 right now, so it comes in here as 200, and it says okay, age is equal to age, which is 10 in this case.

Because 10 is nil, not false, 5 again gets ignored and you end up with 10, but not 200, obviously, because this line does not execute, because this condition is not met.

Class methods and class variables

class MathFunctions 
  def self.double(var) # 1. Using self 
    times_called; var * 2; 
  end 
  class << self # 2. Using << self 
    def times_called 
      @@times_called ||= 0; @@times_called += 1 
    end 
  end 
end 
def MathFunctions.triple(var) # 3. Outside of class 
  times_called; var * 3 
end

# No instance created! 
puts MathFunctions.double 5 # => 10 
puts MathFunctions.triple(3) # => 9 
puts MathFunctions.times_called # => 3 
class Dog 
  def to_s 
    "Dog" 
  end 
  def bark 
    "barks loudly" 
  end 
end 
class SmallDog < Dog 
  def bark # Override 
    "barks quietly" 
  end 
end 

dog = Dog.new # (btw, new is a class method) 
small_dog = SmallDog.new 
puts "#{dog}1 #{dog.bark}" # => Dog1 barks loudly 
puts "#{small_dog}2 #{small_dog.bark}" # => Dog2 barks quietly 

These guys I invoked on the class as opposed to an instance of a class. So if you’re familiar with the concept of a static method in Java, these are your equivalent. Self outside of the method definition refers to the class object, and that’s how you know something is a class method is if it has a self on the outside of method definition.

As we’re gonna see, there are two more ways to define class methods in Ruby besides just having self on the outside of a method definition. And then class variables begin with @@, not just a single @. So single @ symbol gives you an instance variable and double @ symbol gives you a class variable. So to see an example of this, let’s say you have a class called MathFunctions. Now, MathFunctions, maybe it has a bunch of functions like double or triple or something like that.

So maybe it doesn’t make sense to create an object of the MathFunctions, these are just utility functions that are used. Are you gonna double something, you wanna triple something. So, the most obvious way to define the class variable is to say self.double, I guess self dot. And self dot means that it’s a class variable and var multiplied by 2 means that you’re gonna get the actual, in this case, double of what you passed in. And the way this is used is you have MathFunctions.double, and that’s when you pass in 5. You get back 10. And notice how in this case, because it’s a class method, we’re not creating an instance of a class, we’re just calling this double directly on the class itself.

Then, maybe, there’s the method call triple. And the way this triple is defined, notice that this is defined completely outside of a class definition. So class definition is MathFunctions. We just say, outside of the class define the method called MathFuntions.triple which is a class method on a MathFuntions class.

And, again, this method just triples the value that’s passed into it. Notice how you could use parentheses over here, it follows exactly the same rules of method definitions, yes parenthesis, no parenthesis, it’s all fine. And a third way to define class methods is to have it in a way that’s very similar to instance method, so you have, you have def, you have times_called. That’s your regular what you would call an instance method, but it’s defined inside this class, end, and self construct here. And it makes the times_called is also a class method.

So three ways to define them. The way you know that something is a class variable is if it has two @ symbols in front of it. That’s what times_called is. At the end, you have times_called that’s been called three times.
Let’s talk about class inheritance. So every class implicitly inherits from the object class. The object itself inherits from a basic object class.

Ruby does not support multiple inheritance and instead use something called mixins which we’ll be discussing in the next lecture. So let’s see a quick example of inheritance. We have a class called Dog, which implicitly inherits from Object. Right, because it doesn’t inherit from anything. So implicitly, every class inherits from an Object class. Then, maybe you have a SmallDog, which inherits, and that’s what this symbol means. It inherits from a Dog class.

So, like regular inheritance in all OO languages. You have a bark method that the class that inherits from the Dog method can override. So maybe a regular dog barks loudly and the small dog barks quietly. So, you create an instance of a dog method and then, you create an instance of a small dog method. So, dog, whether it was create using the dog class barks loudly and the other one barks quietly.

In summary, class inheritance lets you override parent’s behavior. Class methods do not need an instance of an object in order to be called and class variables begin with @@.

No Comments

Post a Comment