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 (1)

Collapse
 
ankk98 profile image
Ankit Khandelwal

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

Update Your DEV Experience Level:

Settings

Go to your customization settings to nudge your home feed to show content more relevant to your developer experience level. 🛠