skip to content

In Ruby, why are class methods really singleton methods, and what does class << self open inside a class body?

level: middleimportance: must knowfreq 55%

answer

  1. a class is an object too
  2. methods on the class's singleton class
  3. class << self opens it
  4. private works inside it
  5. subclasses inherit class methods

basics

~20 s

A class is an object, so a class method is a singleton method of the class object, stored in its singleton class. class << self opens that singleton class, so def, attr_accessor and private inside it act at class level.

solid answer

~40 s

`Report` is an instance of `Class`, so methods called on `Report` must live somewhere only `Report` uses: its **singleton class**. `def self.build` and a `def build` inside `class << self` both put `build` there, which is why `Report.singleton_methods` lists it and `Report.singleton_class.instance_methods(false)` does too. `class << self` opens that singleton class as a class body, so everything inside applies to the class object: `attr_accessor :config` creates `Report.config`, `private` makes later class methods private, and several class methods can be grouped in one place. A subclass's singleton class inherits from its parent's, so `Subreport.build` works. The classic trap: a bare `private` in the class body does not affect `def self.x`; use `private` inside `class << self` or `private_class_method`.

code

ruby · 21 lines
ruby
class Report
  def self.build = new

  class << self
    attr_accessor :default_format

    def formats = %i[pdf csv]

    private

    def cache = @cache ||= {}
  end
end

class Subreport < Report; end

Report.default_format = :pdf
Report.singleton_methods.sort      # => [:build, :default_format, :default_format=, :formats]
Subreport.build                     # => #<Subreport ...> (inherited class method)
Subreport.singleton_methods(false)  # => []
Report.cache                        # NoMethodError: private method 'cache' called for class Report

go deeper

for a junior

Recall that def self.x and methods inside class << self are both class methods, called on the class rather than its instances.

for a middle

Explain that a class is an object whose class methods live in its singleton class, and show class-level accessors and private class methods inside class << self.

for a senior

Spot the private-trap in reviews, choose private_class_method or class << self deliberately, and explain how subclasses inherit class methods.

for a principal

Pick one house style for class methods so readers know where to look, and reserve class << self for class-level state and private helpers.

## A class is an object In Ruby, `class Report; end` creates an object: an instance of `Class`, assigned to the constant `Report`. Calling `Report.new` or `Report.build` is an ordinary method call on that object. The question is where such methods live, since they must not become methods of every other class. The answer is the same as for any other object with methods of its own: the **singleton class**. Every class object has one, and it holds the class's class methods. "Class method" is a name for a role, not a separate mechanism. ## Two ways to write into the singleton class | Form | What it does | |---|---| | `def self.build` in the class body | defines `build` in `Report`'s singleton class, because `self` is `Report` there | | `def build` inside `class << self` | the same, written inside the singleton class's own body | Both produce the same result: - `Report.singleton_methods` includes `:build`; - `Report.singleton_class.instance_methods(false)` includes `:build`; - `Report.new.respond_to?(:build)` is `false`. ## What class << self adds `class << obj` opens the singleton class of `obj` as a class body; inside a class body, `self` is the class, so `class << self` opens the class's singleton class. Inside it, the usual class-body tools act at **class level**: 1. **`attr_accessor`, `attr_reader`, `attr_writer`** create class-level accessors: `Report.config = {...}` and `Report.config`. 2. **`private` and `protected`** without arguments affect the following `def`s, giving private class methods. 3. **`alias_method`** and **`define_method`** operate on class methods. 4. **Grouping**: many class methods sit together without repeating `self.`. ## The private trap A bare `private` in the class body changes the default visibility of later **instance** methods. `def self.x` does not define an instance method, so it stays public: ```ruby class Report private def self.secret = :still_public end Report.secret # => :still_public ``` Writing `private def self.secret` is worse: `private` receives `:secret` and looks for an instance method of that name, so it raises `NameError`. The two correct forms are `private` inside `class << self`, or `private_class_method :secret` after the definition. ## Inheritance of class methods When `Subreport < Report`, Ruby arranges that `Subreport`'s singleton class inherits from `Report`'s singleton class. So `Subreport.build` finds `Report.build`, `super` inside a redefined class method reaches the parent's version, and `Subreport.singleton_methods` includes the inherited ones unless you pass `false`. ## Looking at the singleton class directly The singleton class is an ordinary `Class` object you can hold in a variable: - `Report.singleton_class` returns it; it inspects as `#<Class:Report>`. - `Report.singleton_class.instance_methods(false)` lists the public and protected class methods `Report` defines itself. - `Report.singleton_class.private_instance_methods(false)` lists private class methods, which `singleton_methods` leaves out. A `class << self` body, like any class body, returns the value of its last expression, so `class << self; self; end` evaluates to the singleton class itself. Older code used that expression to reach the singleton class; `singleton_class` says the same thing directly. ## Choosing a style - `def self.x` is the most common and the easiest to grep. - `class << self` pays off when you need class-level accessors, private class methods, or a long group of class methods. - Mixing both in one class is legal but makes readers look in two places. ## Mistakes to avoid - Describing class methods as a separate kind of method stored in the class itself. - Expecting a bare `private` in the class body to hide `def self.x`. - Writing `private def self.x` and getting `NameError`. - Forgetting that `attr_accessor` inside `class << self` creates class-level, not instance-level, accessors. - Thinking subclasses must redefine class methods to use them.

  • Why does a bare private in the class body not hide def self.secret, and what does?
    A bare `private` sets the default visibility for later instance methods, and `def self.secret` defines a method on the singleton class instead. Put `private` inside `class << self` before the definition, or call `private_class_method :secret` after it. `private def self.secret` fails with `NameError`, because `private` looks for an instance method named `secret`.
  • What does Subreport.singleton_methods return compared with Subreport.singleton_methods(false)?
    With the default argument, it includes class methods inherited from `Report`, because `Subreport`'s singleton class inherits from `Report`'s. With `false`, only class methods defined directly on `Subreport` are listed, which is empty until `Subreport` defines its own.

saying these in an interview costs you the question

  • Class methods are stored in the class alongside its instance methods
  • A bare private in the class body makes def self.x private
  • attr_accessor inside class << self creates instance accessors
  • Subclasses do not inherit class methods
  • class << self opens a new subclass of the class