Everything is object in Ruby? What about class?

Reading time ~6 minutes

In the previous post, I talked about this in JS and self in Ruby.

All the following contents are modified from the talk Dave Thomas give at 2009 Scotland Rails The Ruby Object Model and Metaprogramming in Ruby: It’s All About the Self by Yehuda Katz.

Everything is an object

I said:

Because JS is not like classic OOP, You cannot create another object from the mold(class). Although, it has some similar way(prototype) that you can work like a classic OOP.

Well, I was wrong about Ruby. There is not such things that you create an object from the definition class. You might heard that In Ruby, everything is object. I am confused at first. How could it be possible? class is not an object, you create a thing from the class that define what properties and methods that a object has. So how could it be possible that class is an object?

class is an object called Class. it is different from java or C# that class is a definition

We use the analog that class is a mold of an object. So mold is also an object.

Let’s start with this easy code:

  animal = 'my cat'

  animal.upcase #MY CAT
  animal.object_id #8953720
  animal.bark #NoMethodError 

You assign the string “my cat” to the variable animal, when you call animal.upcase, the variable animal don’t have the methods, so it look right to the class String, there is an methods named upcase. And if we call the object_id method, but it cannot find in the String class. It then look up at the Object class. Bingo, it finds the method.

  String.ancestors #[String, Comparable, Object, Kernel, BasicObject]

You can check the method-look-up chain of a class in Ruby by calling ancestors. If a method cannot find, it will go up to search until it hits the BasicObject. If there is no result there, it will return NoMethodError. If we draw a diagram here:

ruby-model

So, we can have a little deduction here:

  • If we can not find a method, we first go right, then we go up.
  • We can think class as a collective box of method for an object.
  • All the class in Ruby is an object that contains a table of methods.

It is object-oriented, not class-oriented programming

Actually, Ruby knows nothing about the classes, and has no idea on it If you look up the RDoc, you read the first line in Class

Classes in Ruby are first-class objects—each is an instance of class Class.

So it is the instance of class Class. For example, String.class => Class. It means class String is an instance of Class.

  class Animal
  end

  MyCat = Animal.new

When Animal.new is called to create a new object, the new method in Class is run by default.

Give an object a method

Now, we give my cat with some action:

  def animal.speak
   puts 'meow'
  end 

  animal.speak # meows => nil

You give my cat with the ability to meow.

So the same here. Ruby search if there is a method in the my cat? No. Is there a speak in String ? No. Where is the method ?

When you find a method in Ruby, first go to the right, then go up.

Ruby would not want you to see this class, so we call it ghost class, some people will call it meta class or singleton class. the speak method is hiding here.

  animal.class # => String

See? you can not access this ghost class , if you call the class on the object.

ruby-ghost

Let us recap here:

if you invoke speak method, ruby go right to search for it, but it couldn’t find one, so it simply insert the class of that animal object that contains this speak method. We create a thing here that the class pointer of our animal to be that thing.

  class << animal
  puts self
    def climb
      puts 'I can climb'
      puts self
    end
  end

  animal.climb # I can climb => nil

Uhh… What’s going on here? That is another way you give an object a method. In the line 2, if you puts out the self here, as soon as you define the ghost class, it will execute puts self.

It tells you that self here is #<Class:#<String:0x00>>. And if you puts self inside the climb method, it tell you that self here is the object “my cat”.

You might already have known that self in the Ruby will change when you define the class. But It also change when you make a method invoking.


  class D
    def one_method
      @a = 1
      two 
    end

    def two_method
      puts @a
    end

    def three_method
      puts self
    end
  end

  d_object = D.new # self is set to the d_object
  d_object.one_method # we don't change self here(it is the same, self point to d_obejct, ruby search from two method of the d_object)
  d_object.three_method #<D:0x00000001183d68> => nil. self now point to the D class.

More about self

Ruby take animal as a receiver, and set self to be the receiver. Before anything going to happen, Ruby set self to “my cat” object. Ruby then looks for the method at the method-look-up chain. After execution, self pop back to the original state.

It comes down to the fact that all Ruby code is executed code–there is no separate compile or runtime phase. In Ruby, every line of code is executed against a particular self.

  puts self
  class Matz
    puts self
  end
  puts self

  # main
  # Matz
  # main
  1. every line is executable, even when in class definition
  2. self can change when method calling.

Do you know how to define a class method?

  class Matz
    def self.speak
      puts "I can speak Japanese"
    end
  end

  Matz.speak

Easy! Just like that. self here set to the Matz. So If we define a class method. That’s how we do it. But by now, you already have known something:

  1. class is an object of Class
  2. There is no such things about class.

So Just like singleton class, Ruby goes right and builds the ghost class and it finds the speak method there. So Matz.speak can prints out “I can speak Japanese.”

So you can also define:

  class Matz
    class << self
      def speak
        puts "I can speak Japanese"
      end
    end
  end

  Matz.speak

Now we know that << (less than less than) open up the ghost class, then we can dump the methods into it.

Almost every beginner in Ruby have some issue with the following code:

  class Matz
    @home = "Japan"

    def gohome
      @home
    end
  end

  m = Matz.new
  p m.gohome # => nil

There is a bug in Ruby? why m.gohome return nil ? Because instance variable are always set to self. self in line 2 is set to the class object. In the line 5, self here is set to the m object. And they are totally different object. So you can not access the instance variable of the Matz.


  class Matz
    @home = "Japan"

    def self.gohome
      @home
    end
  end

  p Matz.home # => "Japan"
  class Matz
    @home = "Japan"
    class << self
      attr_accessor :home
    end
  end

  p Matz.home # => "Japan"
  Matz.home = "US"
  p Matz.home # => "US"

That’s it. That’s what Ruby talk about everything is an object. And it is the object-oriented programming.

to_param in Ruby on Rails

If I want a custom slug=======================I walk through this cutstom slug.1. create migration `add_slug` to add a column inside the...… Continue reading

What is ORM in Rails mean?

Published on July 14, 2017