12/08/2018, 12:58

[fundamental] Inside Ruby Objects and Classes

As we've already known, Ruby's an OOP language so understanding about Class and Object plays a crucial role when becoming a professional Ruby programmer. In this post, I want to dig into structure and organization of fundamental elements, Object and Class which all of Ruby dev familiar with. 1. ...

As we've already known, Ruby's an OOP language so understanding about Class and Object plays a crucial role when becoming a professional Ruby programmer. In this post, I want to dig into structure and organization of fundamental elements, Object and Class which all of Ruby dev familiar with.

1. Ruby Object

Basically, Ruby doesn't compile and run the application by itself so they need the help from C language. All the Ruby objects are kept in C structure named RObject which's organized like bellow Ruby Object.jpg For easily explaining, I'll take a simple class as an example

class Car
  attr_accessor :type #Sport, Sedan,..
  attr_accessor :cylinder_capacity
end

Each Ruby object's assigned with specific VALUE which's implicit its pointer

RObject contains RBasic inwhich:

  • flags: a set of Boolean values store internal technical values
  • klass: refer to Class created current object
2.1.5 :001 > jimmy_car = Car.new
 => #<Car:0x007f9751a0c6a8>
2.1.5 :002 > jimmy_car.type= "Sports"
 => "Sports"
2.1.5 :003 > jimmy_car.cylinder_capacity= "2.0"
 => "2.0"
2.1.5 :004 > jimmy_car
 => #<Car:0x007f9751a0c6a8 @type="Sports", @cylinder_capacity="2.0">

We can easily detect the Class name is Car while the hexa value 0x007f9751a0c6a8 is implicit VALUE

Besides, RObject also provide two other fields to store instance variable:

  • numiv: the number of instance varibale
  • ivptr: a pointer to an array of values of instance varibales

With above example, numiv, ivptr receive value 2 and point to array ["Sports", "2.0"]

To sum up, we can simplify

Every Ruby object is the combination of a class pointer and an arrays of instance varibales

2. Ruby Class

If we consider each Ruby object as an item in supermarket, the Ruby Class,which created the objects, must be a factory carrying complicated functions and organization. Therefore, I'll go step-by-step to through each part with different features of a Ruby Class. So, Let start with opened summary then it'll be completed when we know everything about Ruby Class

"A Ruby class is"

Methods and attributes

Comming back to first part example with Car class

class Car
  attr_accessor :type #Sport, Family...
  attr_accessor :cylinder_capacity
end

In here, attr_accessor's just a shortcut of group methods aim to defining, getting, setting for attribute. The full version of Car class should be

class Car
  def type
    @type
  end

  def type=(value)
    @type = value
  end

  def cylinder_capacity
    @cylinder_capacity
  end

  def cylinder_capacity=(value)
    @cylinder_capacity = value
  end
end

All these methods appear in every Ruby class which's a group of methods definations. All objects're born by class owning above methods that calling object methods. Then we have first feature of Ruby class

"A Ruby class is a group of methods definations"

In fact, the functions above also used two varibales: @type and @cylinder_capacity and RObject stores just instance varibale values, not their names. So RClass definitely comprises attribute name.

Interestingly, Ruby classes are based on Class class, as a consequence, class is an object. As we conducted above, "Every Ruby object is the combination of a class pointer and an arrays of instance varibales". Now we can visualize some components inside RClass

A Ruby class is a group of method definitions and a table of attribute names.

RClass_step1.jpg

Inheritance

All of us know about inheritance, a siginificant feature of Object-oriented programming and Ruby Classes definitely have this precious gift. To do this, in each Ruby Class, there's a space to specify superclass and in the case we don't have superclass, Ruby will use Object class as the superclass. For example, class Car can be inherited from Vehicle

class Car < Vehicle
  ...

Then now, class Car can use some variables and function which've already defined in Vehicle class. And now, we have a newer version of Ruby Class

A Ruby class is a Ruby object that also contains method definitions, attribute names, and a superclass pointer.

RClass_step2.jpg

Constants

class Car < Vehicle
  EMISSION_STD = "EURO 2"
  ...![RClass_last_step.jpg](/uploads/1a523a5c-d339-4368-9cfe-8b428bd859d1.jpg)

Sometimes, in Class, we need to declare constanst which always start with capital letter. Many people refer constants as global varibale of Ruby Class, actually its properties have some differences with variable such as warning when changing constant value. Therefore, our RClass cannot skip this part

A Ruby class is a Ruby object that also contains method definitions, attribute names, a superclass pointer, and a constants table.

Then now we own a completed view about Ruby Class RClass_last_step.jpg

3. Specialities of Ruby class

We've already known how Ruby Object and Class are constructed but I think there're some vague points for us when using RClass. This part'll point out two most confusing features of Ruby Class

Class Instance Variable vs Class Variables

Let add some variables to our Car classs

class Car < Vehicle
  ...
  @engine = "Diesel"
  @@automative_electronics = true
  class << self
    def engine_name
      @engine
    end

    def electronics_controlling?
      @@automative_electronics
    end
  end
end

Now our Car class has two new variables:

  • @engine: class instance variable
2.1.5 :001 > Car.engine_name
 => "Diesel"
  • @automative_electronics: class varibale
2.1.5 :002 > Car.electronics_controlling?
 => true

So are two kind of varibales just dirrerent to each other in syntax? It's not exactly. Let define a BMW class inherited from Car

class Car
  ...
  @engine = "Diesel"
  @@automative_electronics = true
  ...
end

class BMW < Car
  @engine = "Hybrid"
  @@controlling = "Electronics"
end

puts "#{Car.engine} vs #{ BMW.engine}"
puts "#{Car.controlling} vs #{BMW.controlling}"

And this's result when running class above

Diesel vs Hybrid
Electronics vs Electronics

It's clear that @engine only has effect inside clas and it'll be changed in different class. Meanwhile, @@controlling is shared between parent class and its subclasses and as a consquence, RClass need to store both these two kind of variables

Methods class

I guess that all of us has the main concept of class methods and object method. On the previous part, we can see that RClass create methods for object by methods table. So where does Ruby keep class method? Let try with an IRB session

2.1.5 :001 > ObjectSpace.count_objects[:T_CLASS]
 => 887
2.1.5 :002 > class Toyota; end
 => nil
2.1.5 :003 > ObjectSpace.count_objects[:T_CLASS]
 => 889

I used ObjectSpace to count all of available clases but there're something abnormal in here. We created just one class named Toyota but 2 more classes were added to :T_CLASS. The answer is Ruby automatically added an additional metaclass which store class methods of Toyota class. However, we cannot see this metaclass by normal way.

2.1.5 :007 > Toyota.singleton_class
 => #<Class:Toyota>
Toyota.singleton_class.methods
 => [:nesting, :constants, :allocate, ...]

4. The bottom line

This post is quite longer so I really want to say "Thank you" for anyone scrolling to this line. I hope that my post will help all of you to get insights into Ruby clasess and objects.

0