What does "class << self" actually do in Ruby?

As a ruby developer, you almost certainly have seen class << self definition inside a class. Methods defined within class << self block become class methods. Here's an example.

class Greeting
  class << self
    def hello
      puts "Hello!"
    end
  end
end

Now hello method can be called on the Greeting class.

>> Greeting.hello
Hello!

You can also add a class method like this.

class Greeting
  def self.hello
    puts "Hello!"
  end
end

The end result will be the same. Does it mean that class << self is simply a syntactic sugar that allows adding class methods? Not exactly. To understand what class << self actually does, we must first understand what self is inside a class.

What is self?

There's always a self object at any point in the Ruby code. Outside of any class/module/method definitions, self is a main object of the class Object.

>> puts self, self.class
main
Object

Inside a method within a class, self is the object of that class.

class Greeting
  def whoami
    puts self, self.class
  end
end
>> Greeting.new.whoami
#<Greeting:0x00007ff03c8f6e78>
Greeting

And, within a class but outside of any method, self is the class object. In Ruby, classes are objects too. Every class is an object of the Class class.

class Greeting
  puts self       # Greeting
  puts self.class # Class
end

Using class << obj instead class << self

Now that we know that self is simply a class object, let's try to replace it with the actual class name and see how that works.

class Greeting
  class << Greeting
    def hello
      puts "Hello!"
    end
  end
end

Works like a charm 😎

>> Greeting.hello
Hello!

So, class << Greeting is that same as class << self. Methods inside that block get added to the Greeting class object. But wait, since Greeting is an object, can we replace it with any other object? Can we use a non-class object? Let's try.

obj = Object.new
class << obj
  def hello
    puts "Hello!"
  end
end
>> obj.hello
Hello!

Hmm... We are able to add methods to any object!
Amazing

What class << self actually does

Turns out that class << ... doesn't necessarily have to be used with class objects. You can use it with any object.

So far we learned that:

  1. Method defined within class << obj block will be added to the obj object.
  2. obj can be any object.

class << self definition is used often within a class, that new Ruby developers might think that it's some kind syntactic sugar available only for classes which allows to add class methods. But now we know that it's not true.

Singleton class

There's one more thing worth mentioning. class << obj block opens a singleton class. Every Ruby object has a singleton class. Methods defined within class << obj block are instance methods of the singleton class of the object obj 🤯 The most important thing to remember is that singleton class instance methods take precedence in the method lookup process. This example should explain more.

class Greeting
  def hello
    puts "Hello!"  
  end
end

obj = Greeting.new

class << obj
  def hello
    puts "Hola!"
  end
end
>> obj.hello
Hola!

Singleton class is a regular class object which you can access using #singleton_class method. This method is available for all objects.

>> puts obj.singleton_class, obj.singleton_class.class
#<Class:#<Object:0x00007faf18146648>>
Class

Since it's just a class, you can list its instance methods.

# Let's add one more method for the sake of example.
class << obj
  def hola
    puts "Hola!"
  end
end
>> obj.singleton_class.instance_methods(false)
=> [:hola, :hello]

The last thing I'd like to mention about the singleton class is that you can also define its instance methods using this syntax.

def obj.hello
  puts "Hello!"
end

I hope now you see that all class methods(no matter whether they are defined using class << self or def self.method syntax) are actually instance methods of the singleton class of the class object.
What

Conclusion

  1. class << obj block opens a singleton class 🙃
  2. In that block we can defined instance methods of the singleton class 🧐
  3. Those methods take precedence in the method lookup process 🚀
  4. Singleton class is a regular class object 😁
  5. Every Ruby object has its own singleton class which can be accessed via #singleton_class method 😎

30