Skip to main content

Command Palette

Search for a command to run...

The Ruby Koans: About Class Methods

Updated
4 min read

The Ruby Koans are a fantastic resource to introducing the concepts and syntax of the Ruby programming language. In this post, we’ll explore the concepts posed by about_class_methods.rb: class methods, instance methods, and singleton methods.

Objects, Classes, and Class Objects

Let's start with some fundamental truths:

  • Instances of a class are objects.

  • A class itself is an instance of Class.

  • Since classes are objects, they can have their own methods.

Objects are instances of a class

class Dog
end

fido = Dog.new
puts fido.is_a?(Object)  # => true

Every object in Ruby inherits from Object, so even instances of Dog are objects.

Classes are objects too

puts Dog.is_a?(Class)  # => true
puts Dog.is_a?(Object) # => true

Since Dog itself is an instance of Class, it is both a class and an object at the same time.

Instance Methods vs. Class Methods

Instance methods are methods that belong to a specific instance of a class and operate on that instance’s data, whereas class methods belong to the class itself and can be called without creating an instance.

Defining an Instance Method

class Dog
  def wag
    :instance_level_wag
  end
end

fido = Dog.new
puts fido.wag  # => :instance_level_wag

Here, wag is an instance method. Each instance of Dog (e.g., fido) can call this method.

Defining a Class Method

There are multiple ways to define class methods:

Using self.method_name

class Dog
  def self.class_method
    :dogs_class_method
  end
end

puts Dog.class_method  # => :dogs_class_method

By using self. inside the class definition, we define a class method directly on Dog.

Using class << self (Singleton Class Syntax)

class Dog
  class << self
    def another_class_method
      :still_another_way
    end
  end
end

puts Dog.another_class_method  # => :still_another_way

This technique defines class methods using the singleton class, which is a special, hidden class that Ruby creates for each object to hold methods specific to that object. A singleton class (also called a metaclass or eigenclass) is unique to each object and allows defining methods that only that particular object can access. In this case, class << self opens up the singleton class of Dog, allowing us to define methods that belong only to the Dog class itself.

For example:

class Dog
  class << self
    def bark
      'Woof!'
    end
  end
end

puts Dog.bark  # => 'Woof!'

This is equivalent to:

class Dog
  def self.bark
    'Woof!'
  end
end

puts Dog.bark  # => 'Woof!'

Singleton methods can also be applied to individual instances:

fido = Dog.new

def fido.speak
  'Arf!'
end

puts fido.speak  # => 'Arf!'

However, this method is only available to fido, not other instances of Dog.

Singleton Methods on Objects

Since everything in Ruby is an object, we can define methods on individual instances:

fido = Dog.new

def fido.wag
  :fidos_wag
end

puts fido.wag  # => :fidos_wag

However, this method only applies to fido, not other Dog instances:

rover = Dog.new
puts rover.wag  # => NoMethodError

Class Instance Variables vs. Instance Variables

Instance variables inside a class belong to instances of that class, whereas instance variables inside the class definition itself belong to the class object.

class Dog
  attr_accessor :name
end

def Dog.name
  @name
end

fido = Dog.new
fido.name = "Fido"

puts fido.name  # => "Fido"
puts Dog.name   # => nil

The instance variable @name on fido does not affect Dog because Dog.name refers to an instance variable on the class object, not on an instance.

The Value of self in a Class Definition

Inside a class definition, self refers to the class itself:

class Dog
  puts self  # => Dog
end

Since self refers to the class, we can define class methods like this:

class Dog
  def self.class_method2
    :another_way_to_write_class_methods
  end
end

puts Dog.class_method2  # => :another_way_to_write_class_methods

Returning Values from Class Definitions

In Ruby, the last expression inside a class definition determines its return value:

LastExpression = class Dog
                   21
                 end

puts LastExpression  # => 21

For example, this behavior can be used in metaprogramming to dynamically define constants or class-level settings based on computations performed within the class definition:

DefaultLimit = class Configuration
                 100 * 2
               end

puts DefaultLimit  # => 200

Here, the last evaluated expression (100 * 2) is returned and assigned to DefaultLimit.

Calling Class Methods from Instances

Although class methods belong to the class, instances can still access them indirectly:

fido = Dog.new
puts fido.class.another_class_method  # => :still_another_way

This works because fido.class evaluates to Dog, and Dog.another_class_method is a valid class method.

Which Class Method Syntax Should You Use?

Both of the following approaches work for defining class methods:

class Demo
  def self.method_one
  end

  class << self
    def method_two
    end
  end
end

Which one should you prefer?

  • self.method_name is more common and easier to read. This is usually what you should do.

  • class << self is useful when defining multiple class methods at once.

Hopefully this post has clarified some key concepts in this chapter of the Koans. As you continue your Ruby journey, may you keep in mind (my personal favorite axiom from the test output): mountains are merely mountains.