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
selfalways 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
selfexplicitly when calling setter methods inside a class class << selfopens the singleton class โ useful for grouping class methods- Returning
selffrom methods enables method chaining (builder/fluent patterns)
Comments