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

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 object

2️⃣ 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.describe

When 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: 3

Common Errors (and the fix)

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 here

Pro Tips

📋 Quick Reference — self & Class-Level Code

ConceptRuby Syntax
Class methoddef self.name ... end
Many class methodsclass << self ... end
Class variable (shared)@@count = 0
Class instance var@count (in class scope)
Class-level accessorclass << self; attr_accessor :x; end
Current objectself

🎉 Lesson Complete!

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

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.