Skip to main content
โšก Calmops

Understanding self in Ruby

Introduction

In Ruby, self is a special variable that always refers to the current object โ€” the object that is receiving the current message (method call). Understanding self is fundamental to mastering Ruby’s object model, metaprogramming, and class design.

Unlike some languages where this is implicit, Ruby makes self explicit and its value changes depending on where you are in the code.

What Does self Refer To?

The value of self depends on the context:

Context self refers to
Top-level main (the main object)
Inside a class body The class itself
Inside an instance method The instance receiving the call
Inside a class method The class itself
Inside a module The module
Inside a singleton method The object the method is defined on

self at the Top Level

At the top level of a Ruby script, self refers to main, a special instance of Object:

puts self        # => main
puts self.class  # => Object

self Inside a Class Body

When you’re inside a class definition (but outside any method), self refers to the class object itself:

class Dog
  puts self        # => Dog
  puts self.class  # => Class
end

This is why class-level code like attr_accessor or custom DSL methods work โ€” they’re called on the class object.

self Inside Instance Methods

Inside an instance method, self refers to the specific instance that received the method call:

class Dog
  def initialize(name)
    @name = name
  end

  def who_am_i?
    puts self         # => #<Dog:0x00007f...>
    puts self.class   # => Dog
    puts self.object_id
  end

  def greet
    "Hi, I'm #{self.name}"
  end

  def name
    @name
  end
end

rex = Dog.new("Rex")
rex.who_am_i?
puts rex.greet  # => Hi, I'm Rex

self Inside Class Methods

Inside a class method, self refers to the class:

class Dog
  def self.species
    "Canis lupus familiaris"
  end

  def self.describe
    "I am the #{self} class"
  end
end

puts Dog.species   # => Canis lupus familiaris
puts Dog.describe  # => I am the Dog class

Both def self.method_name and class << self are common patterns for defining class methods.

self and Explicit vs Implicit Receiver

In Ruby, you can often omit self when calling methods on the current object. However, there are cases where you must use it explicitly.

When self is Optional

class Person
  def initialize(name, age)
    @name = name
    @age  = age
  end

  def introduce
    # Both are equivalent โ€” self is implicit
    "My name is #{name} and I am #{age} years old."
  end

  def name; @name; end
  def age;  @age;  end
end

When self is Required: Setter Methods

You must use self when calling setter methods inside a class, otherwise Ruby interprets it as a local variable assignment:

class Person
  attr_accessor :name

  def rename(new_name)
    # WRONG: creates a local variable, does NOT call the setter
    name = new_name

    # CORRECT: calls self.name=()
    self.name = new_name
  end
end

p = Person.new
p.rename("Alice")
puts p.name  # => "Alice" (only works with self.name = ...)

self in Singleton Methods

A singleton method is defined on a specific object, not its class. Inside it, self is that object:

dog = Object.new

def dog.speak
  "#{self} says: Woof!"
end

puts dog.speak  # => #<Object:0x...> says: Woof!

self in Modules

Inside a module, self refers to the module itself:

module Greetable
  puts self  # => Greetable

  def self.version
    "1.0"
  end

  def greet
    "Hello from #{self.class}"
  end
end

puts Greetable.version  # => 1.0

class Robot
  include Greetable
end

puts Robot.new.greet  # => Hello from Robot

class « self Pattern

The class << self syntax opens the singleton class of the current object. It’s commonly used to define multiple class methods at once:

class Config
  class << self
    def default_timeout
      30
    end

    def default_retries
      3
    end

    def settings
      { timeout: default_timeout, retries: default_retries }
    end
  end
end

puts Config.default_timeout  # => 30
puts Config.settings.inspect # => {:timeout=>30, :retries=>3}

This is equivalent to prefixing each method with def self., but cleaner when you have many class methods.

Practical Example: Builder Pattern with self

self enables fluent/chainable interfaces by returning the current object:

class QueryBuilder
  def initialize
    @conditions = []
    @limit = nil
  end

  def where(condition)
    @conditions << condition
    self  # return self for chaining
  end

  def limit(n)
    @limit = n
    self
  end

  def build
    sql = "SELECT * FROM table"
    sql += " WHERE #{@conditions.join(' AND ')}" unless @conditions.empty?
    sql += " LIMIT #{@limit}" if @limit
    sql
  end
end

query = QueryBuilder.new
  .where("age > 18")
  .where("active = true")
  .limit(10)
  .build

puts query
# => SELECT * FROM table WHERE age > 18 AND active = true LIMIT 10

Common Pitfalls

Forgetting self on Setter Calls

class User
  attr_accessor :email

  def update_email(new_email)
    email = new_email      # BUG: local variable, not the setter
    self.email = new_email # CORRECT
  end
end

Confusing Class and Instance Context

class Counter
  @@count = 0

  def initialize
    @@count += 1
    puts "Instance self: #{self}"       # the new instance
    puts "Instance class: #{self.class}" # Counter
  end

  def self.count
    puts "Class self: #{self}"  # Counter
    @@count
  end
end

Counter.new
Counter.new
puts Counter.count  # => 2

Summary

  • self always refers to the current object receiving the message
  • At the top level it’s main; inside a class body it’s the class; inside an instance method it’s the instance
  • Use self explicitly when calling setter methods inside a class
  • class << self opens the singleton class โ€” useful for grouping class methods
  • Returning self from methods enables method chaining (builder/fluent patterns)

Resources

Comments