DEV Community

Vitalii Paprotskyi
Vitalii Paprotskyi

Posted on

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


Enter fullscreen mode Exit fullscreen mode

Now hello method can be called on the Greeting class.



>> Greeting.hello
Hello!


Enter fullscreen mode Exit fullscreen mode

You can also add a class method like this.



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


Enter fullscreen mode Exit fullscreen mode

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


Enter fullscreen mode Exit fullscreen mode

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



class Greeting
  def whoami
    puts self, self.class
  end
end


Enter fullscreen mode Exit fullscreen mode


>> Greeting.new.whoami
#<Greeting:0x00007ff03c8f6e78>
Greeting


Enter fullscreen mode Exit fullscreen mode

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


Enter fullscreen mode Exit fullscreen mode

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


Enter fullscreen mode Exit fullscreen mode

Works like a charm 😎



>> Greeting.hello
Hello!


Enter fullscreen mode Exit fullscreen mode

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


Enter fullscreen mode Exit fullscreen mode


>> obj.hello
Hello!


Enter fullscreen mode Exit fullscreen mode

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


Enter fullscreen mode Exit fullscreen mode


>> obj.hello
Hola!


Enter fullscreen mode Exit fullscreen mode

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


Enter fullscreen mode Exit fullscreen mode

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


Enter fullscreen mode Exit fullscreen mode


>> obj.singleton_class.instance_methods(false)
=> [:hola, :hello]


Enter fullscreen mode Exit fullscreen mode

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


Enter fullscreen mode Exit fullscreen mode

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 😎

Top comments (5)

Collapse
 
ostap profile image
Ostap Brehin • Edited

Great explanation! and I can see that def self.method_name is similar to static methods in PHP or Java.

Collapse
 
ankk98 profile image
Ankit Khandelwal

We need to read this 2-3 times to actually appreciate this.

Collapse
 
bengalamx profile image
Bengala

So what is better? "class << self" or "class_methods do"

Collapse
 
vitaliipaprotskyi profile image
Vitalii Paprotskyi

class_methods do is a bit different thing that is not part of Ruby language, but Active Support gem. You can read about it in the official documentation

Collapse
 
bengalamx profile image
Bengala

Yes sorry and thanks. I found out are meant for concerns.