self, Class Methods & Class Variables
Reviewed & published by Brayan K
In Ruby, self is a keyword that points at the current object, and it is the key to understanding class methods, the singleton class, and how class-level state is stored.
Part of the free Ruby course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.
You'll learn what self means in each context, how to write class methods with def self.method and class << self, and why @@class variables are a trap you can avoid.
What You'll Learn in This Lesson
- What self means at the top level, in a class, and in a method
- Defining class methods with def self.method
- Using class << self for many class methods
- Class variables (@@var) and how they are shared
- The subclass @@variable overwrite pitfall
- Class instance variables as the safer alternative
1️⃣ What Is self?
There is always a current object in Ruby, and self names it. At the top level it's the special main object; inside a class body it's the class; inside an instance method it's the object the method was called on. Reading self in each spot tells you exactly which object owns the code running there.
# `self` means different things depending on WHERE you are.
puts self # at the top level, self is the "main" object
class Robot
puts self # inside a class body, self is the class itself (Robot)
def whoami
self # inside an instance method, self is THIS object
end
end
r = Robot.new
puts r.whoami.class # => Robot (an instance)
puts r.equal?(r.whoami) # the method returns the very same object2️⃣ Class Methods: def self.method and class << self
A class method is called on the class itself, not on an instance — like Time.now or Array.new. The most common way to write one is def self.name. These make great factory methods that build and return a configured object.
# A class method belongs to the CLASS, not to instances.
# Define one with `def self.name`.
class Temperature
def self.from_celsius(c) # class method (a "factory")
new(c * 9.0 / 5 + 32) # `new` here means Temperature.new
end
def initialize(fahrenheit)
@fahrenheit = fahrenheit
end
def to_s
"#{@fahrenheit}°F"
end
end
# Call it ON THE CLASS, no instance needed:
t = Temperature.from_celsius(100)
puts t # => 212.0°F
# Another common class method:
class Widget
def self.describe
"Widgets are reusable UI parts"
end
end
puts Widget.describeWhen a class has several class methods, repeating def self. gets noisy. Open the singleton class once with class << self and define them all inside, just like ordinary methods.
# `class << self` opens the class's "singleton class" so you can define
# several class methods in one block (handy when you have many).
class Logger
class << self
def info(msg)
"INFO: #{msg}"
end
def warn(msg)
"WARN: #{msg}"
end
end
end
puts Logger.info("started")
puts Logger.warn("low disk")3️⃣ Class Variables (@@) vs Class Instance Variables
A @@variable stores state at the class level and is shared by the class and all of its subclasses through one slot. That sharing is occasionally what you want — but it bites hard in inheritance, because a subclass assigning to the same name overwrites the parent's value. A class instance variable (a plain @var written in class scope) gives each class its own private copy instead.
# @@class_variable is SHARED across the class AND all subclasses.
# That sharing is the famous pitfall.
class Account
@@count = 0 # one variable shared by every Account
def initialize
@@count += 1
end
def self.count
@@count
end
end
Account.new
Account.new
puts Account.count # => 2
# THE PITFALL: subclasses share the SAME @@variable.
class Base
@@registry = "base"
def self.registry; @@registry; end
end
class Sub < Base
@@registry = "sub" # this OVERWRITES Base's @@registry too!
end
puts Base.registry # => sub (surprise!)
# Safer: a class INSTANCE variable (@var in class scope) is NOT shared.
class Counter
@total = 0 # belongs to Counter only, not subclasses
class << self
attr_accessor :total
end
end
class SubCounter < Counter
end
Counter.total = 5
SubCounter.total = 99
puts Counter.total # => 5 (independent!)
puts SubCounter.total # => 99🎯 Your Turn
Fill in the two blanks so User.total reports how many users were created. The shared @@total counter is appropriate here because there are no subclasses to surprise.
# 🎯 YOUR TURN — fill in the blanks (___) then run: ruby user.rb
class User
@@total = 0 # shared count of all users
def self.total # ___ a class method that returns @@total
@@total
end
def initialize(name)
@name = name
@@total += 1 # ___ increment the shared counter
end
end
User.new("Ada")
User.new("Linus")
User.new("Grace")
puts User.total # ✅ Expected: 3Common Errors (and the fix)
- ❌ Calling a class method on an instance: Temperature.new(0).from_celsius(100) raises NoMethodError. ✅ Fix: call class methods on the class: Temperature.from_celsius(100).
- ❌ Forgetting self: def from_celsius(c) makes an INSTANCE method by mistake. ✅ Fix: write def self.from_celsius(c) for a class method.
- ❌ Subclass overwrites @@var: a subclass assigning a @@variable silently changes the parent's value. ✅ Fix: use a class instance variable (@var in class scope) with accessors.
- ❌ self.attr = inside a method without setter: assigning self.name = "x" fails if there's no attr_writer :name. ✅ Fix: add attr_accessor :name or assign the @name ivar directly.
Mini-Challenge: A Factory with a Safe Counter
Combine everything: a class method factory that also tracks how many objects it has built — using a class instance variable so subclasses wouldn't interfere. Run with ruby book.rb.
# 🎯 MINI-CHALLENGE: a class-method factory with a SAFE counter.
# Save as book.rb and run with: ruby book.rb
#
# 1. Give Book a class INSTANCE variable @count (NOT @@count).
# 2. Add a class method Book.published(title) that builds a Book,
# bumps the count, and returns the new book.
# 3. Expose Book.count so you can read the total.
#
# ✅ Expected output:
# "Ruby Basics"
# "Self Explained"
# Total books: 2
# your code herePro Tips
- 💡 Print self while learning: drop a puts self anywhere to see which object owns the code.
- 💡 Prefer class instance variables: reach for @var + accessors over @@var in any class that might be subclassed.
- 💡 Factories read well: def self.build(...) beats sprinkling setup logic across the caller.
📋 Quick Reference — self & Class-Level Code
| Concept | Ruby Syntax |
|---|---|
| Class method | def self.name ... end |
| Many class methods | class << self ... end |
| Class variable (shared) | @@count = 0 |
| Class instance var | @count (in class scope) |
| Class-level accessor | class << self; attr_accessor :x; end |
| Current object | self |
🎉 Lesson Complete!
- ✅ self is the current object — class in a class body, instance in a method
- ✅ def self.method defines a class method
- ✅ class << self groups many class methods and accessors
- ✅ @@variables are shared with subclasses — a common pitfall
- ✅ Class instance variables (@var) keep per-class state safely
Practice quiz
What does self refer to inside an instance method?
- The class itself
- The main object
- The object the method was called on
- nil
Answer: The object the method was called on. Inside an instance method, self is the particular instance the method was called on.
What does self refer to inside a class body (not in a method)?
- The class itself
- The instance
- The superclass
- main
Answer: The class itself. Inside a class body, self is the class itself — which is why def self.foo defines a class method.
How do you define a class method called build?
- def build
- def @build
- class build
- def self.build
Answer: def self.build. def self.build defines a method on the class object, i.e. a class method.
What is class << self used for?
- Inheriting from self
- Opening the singleton class to define several class methods
- Freezing the class
- Creating an instance
Answer: Opening the singleton class to define several class methods. class << self opens the singleton class so you can group many class methods and class-level accessors.
A @@class variable is shared by...
- The class and all of its subclasses
- Only the class
- Only instances
- Nothing — each instance gets its own
Answer: The class and all of its subclasses. A @@variable is shared by the class and every subclass through one storage slot — the famous pitfall.
Given class Base with @@r = "base", then class Sub < Base sets @@r = "sub". What does Base.r return?
- "base"
- nil
- "sub"
- an error
Answer: "sub". The subclass overwrites the SAME @@r, so Base.r returns "sub" — the pitfall in action.
What is the safer alternative to @@class variables for per-class state?
- Global variables
- Class instance variables (@var in class scope)
- Local variables
- Constants only
Answer: Class instance variables (@var in class scope). A class instance variable (a plain @var written in class scope) gives each class its own independent copy.
How do you call a class method named from_celsius on the Temperature class?
- Temperature.new.from_celsius(100)
- from_celsius(100)
- Temperature::new(100)
- Temperature.from_celsius(100)
Answer: Temperature.from_celsius(100). Class methods are called on the class itself: Temperature.from_celsius(100).
If you write def from_celsius(c) (without self) inside a class, what do you get?
- A class method
- An instance method
- A syntax error
- A constant
Answer: An instance method. Without self, def from_celsius defines an INSTANCE method by mistake.
What does self refer to at the top level of a Ruby script?
- nil
- Object
- The special main object
- The first class defined
Answer: The special main object. At the top level, self is a special object called main.
Continue this course
- Previous: Inheritance & super
- Next: Constants & Freezing — Constant scoping with ::, freeze/frozen?, and frozen string literals
- Quick reference: Ruby cheat sheet
Frequently asked questions
What does self actually refer to in Ruby?
self is a keyword that always points at the 'current object' — but which object that is depends on context. At the top level of a script, self is a special object called main. Inside a class or module body, self is the class/module itself, which is why def self.method defines a class method. Inside an instance method, self is the particular instance the method was called on. Tracking what self is at each point is the single most useful skill for understanding Ruby's object model.
What's the difference between def self.method and class << self?
Both define class methods (methods you call on the class rather than on an instance). def self.foo defines a single class method inline. class << self opens the class's singleton class so you can define many class methods together, use attr_accessor for class-level state, and treat the class like any other object. They're interchangeable for one method; class << self shines when you have several class methods or want class-level accessors.
Why are @@class variables considered dangerous?
A @@variable is shared by the class and every subclass through the same storage slot. If a subclass assigns to a @@variable that the parent also uses, it silently overwrites the parent's value — and vice versa. That shared mutation causes surprising bugs in inheritance hierarchies. The modern Ruby recommendation is to prefer class instance variables (a plain @var written in class scope) with class-level accessors, because each class keeps its own independent copy.
When should I use a class method instead of an instance method?
Use a class method when the behaviour doesn't depend on a particular instance: factory methods that build and return objects (like Time.now or Temperature.from_celsius), utility helpers, or operations over the whole collection of instances. Use an instance method when the behaviour needs the data inside one specific object (its @instance variables). A good rule of thumb: if you find yourself writing SomeClass.new just to call a method, that method probably wants to be a class method.