Blaix Blog

Ruby Selfie


I don't do much ruby these days, but I always loved the object model and nature of self in the language. The more I learned about it, the more cool and fun things I could do. And then there's that special feeling when the infamous extend self and class << self stopped feeling like magic incantations, and just made sense in the context of ruby's object model. It started with the understanding that everything in ruby is an object which is an instance of a class. Even classes themselves are objects that are instances of the class Class.

class Dog

puts Dog.class # => Class

When you use the class keyword, you are "opening" a class to define instance methods for any instance of the class:

class Dog
  def bark
    puts "bark!"

dog1 =
dog2 =

dog1.bark # => "bark!"
dog2.bark # => "bark!"

But class instance methods are really class methods on the class's singleton class.

Every object in ruby has an "invisible" singleton class (a metaclass):

puts Dog.singleton_class     # => #<Class:Dog>
puts # => #<Class:#<Dog:0x0123...>>
puts # => #<Class:#<Dog:0x0456...>>

When you say def <some object>.<some method>, you are defining an instance method on that object's singleton class:

def dog1.bark
  puts "redefined bark!"

When you call a method in ruby, it first checks the object's singleton class:

dog1.bark # => redefined bark!
dog2.bark # => bark!

Since classes are objects, the same applies:

  puts "yum!"

We defined an instance method on the class object's singleton class (wee), and method lookup works the same way. There's nothing special about "class" methods in ruby! # => "yum!"

Also, there's always an implicit self object:

puts self # => main

and when you open a class, self changes to the class object:

class Dog
  puts self # => Dog

So when you define "class methods" in ruby like this:

class Dog
  def self.eat_again
    puts "yummy!"

Dog.eat_again # => yummy!

You're using the same def <some object>.<some method> pattern, which defines instance methods on the object's singleton class, and here object is the class object. Radical!

Another way to define methods in ruby is with modules:

module Pisser
  def piss
    puts "pisss"

Classes have a method called include which takes a module and adds the module methods to the class as instance methods:

dog1.piss # => pisss
dog2.piss # => pisss

Classes also have a method called extend which is described as adding "class methods" to the class, but to understand extend self, you need to understand that really extend is adding instance methods to the class' singleton class. Class methods are a ruby myth!

Dog.piss # => pisss

Also remember that using class Whatever is just opening the Whatever class, and self becomes the class, which means this is the same as calling Dog.extend(Pisser):

class Dog
  extend Pisser # => here the implicit `self` is `Dog`

The same thing applies to modules....

module AnotherPisser
  extend Pisser

AnotherPisser.piss # => pisss

Which means we can define modules to namespace "functions" (that are really just instance methods on the module's singleton class):

module Util
  extend self # => the same as Util.extend(Util)

  # Since Util extends itself, these methods will exist on Util's singleton
  # class, making them callable directly on Util
  def hello
    puts "hello"

Util.hello # => hello

Another way to define methods on an object's singleton class is with the class << <object> syntax. For example:

class << dog1
  def pet
    puts "tail wag!"
end # => tail wag!

Which means...

class Dog
  class << self
    def zen
      puts "ruby is radical!"

Inside the Dog class, self is the Dog class object, so class << self opens the Dog class object's singleton class to define methods, and ruby checks the singleton class first on method lookups:

Dog.zen # => ruby is radical!

The easy way to think about it is extend self is a convenient way to define "module methods" and class << self is a convenient way to define "class methods", but understanding the object model and method lookup shows there is nothing special going on. It's all just instance methods on objects.