skip to content

In Ruby, how do a bare private section, private with a symbol list and private attr_reader differ, and what does a section miss?

level: middleimportance: should knowfreq 48%

answer

  1. no args: default for later defs
  2. symbols: existing methods only
  3. array argument accepted since 3.0
  4. each class body starts public
  5. def self.x ignores the section

basics

~20 s

A bare private makes later defs in that class body private; private :a, :b changes named existing methods; private attr_reader :x works since Ruby 3.0. A section does not affect def self.x class methods or other class bodies.

solid answer

~40 s

Called with no arguments, `private` sets the default visibility for methods defined later in the same class body; `protected` and `public` work the same way. It lasts until another modifier or the end of that body, so a reopened `class Salary` starts public again. Called with names, `private :audit, :log` changes only those methods, which must already exist, or it raises `NameError`. Since Ruby 3.0 the modifiers also accept an Array, and `attr_*` return one, so `private attr_reader :amount` makes a private reader in one line. The section form never touches `def self.build`: singleton definitions are always public, so class methods need `private_class_method`. Return values: no arguments gives `nil`, one argument returns it, several return an Array.

code

ruby · 18 lines
ruby
class Salary
  private                          # returns nil

  def self.build(cents) = new(cents)  # still public: singleton def
  def audit = :ok                     # private
end

Salary.build(1)                    # works
Salary.new.audit                   # NoMethodError: private method 'audit' called

class Salary
  p private(attr_reader(:amount))  # => [:amount], private reader
end

class Payslip
  private :render                  # NameError: undefined method 'render' for class 'Payslip'
  def render = nil
end

go deeper

for a junior

Recall both spellings: a bare private line for everything below it, or private :name for specific existing methods.

for a middle

Explain the section's scope per class body, that singleton defs ignore it, that named methods must exist, and the Ruby 3.0 change enabling private attr_reader.

for a senior

Show you can spot visibility bugs in review: class methods accidentally public under a private section, reopened classes exposing helpers, and inherited methods that should be narrowed.

for a principal

Set a consistent visibility style for a codebase, choosing between section and list forms so the public interface of each class is obvious to readers and reviewers.

## Two ways to call the same method `public`, `protected` and `private` are ordinary methods on `Module`, called inside a class body. What they do depends on their arguments: | Call | Effect | Returns | |---|---|---| | `private` | later `def`s in this class body become private | `nil` | | `private :audit` | the existing method `audit` becomes private | `:audit` | | `private :audit, :log` | both named methods become private | `[:audit, :log]` | | `private [:audit, :log]` | same, Array form (Ruby 3.0+) | `[:audit, :log]` | Names may be Symbols or Strings. ## The section form A bare `private` on its own line changes the **default visibility** for methods defined after it: - It applies to `def` and to `attr_reader`, `attr_writer` and `attr_accessor` calls that follow. - It lasts until the next bare `public`, `protected` or `private`, or until the class body ends. - **Every class body starts public.** Reopening `class Salary` later, in another file for example, begins with public methods again; the earlier section does not carry over. ```ruby class Salary def to_s = "salary" # public private def audit = nil # private attr_reader :amount # private reader end class Salary def report = nil # public again: new class body end ``` ## The symbol-list form With arguments, the modifier changes only the named methods and leaves the default alone: 1. The methods must **already exist** in the class or its ancestors. `private :audit` above `def audit` raises `NameError` (`undefined method 'audit' for class 'Salary'`). 2. It is often written at the bottom of a class, listing what is internal. 3. It is the form to use when the visibility of one method must change, for example making an inherited public method private in a subclass. ## Wrapping attr_reader Since **Ruby 3.0**, the `attr_*` helpers return an Array of the method names they define, and the modifiers accept an Array. Together they allow: ```ruby private attr_reader :amount # private reader protected attr_reader :currency # protected reader ``` On Ruby 2.x this raised, because `attr_reader` returned `nil`. ## What a section misses - **Class methods defined with `def self.build`.** A singleton-method definition is always public, whatever section it sits in. Make it private with `private_class_method :build`. - **Methods defined in another class body**, including a reopened one, as described above. - **Methods added from outside the body**, for instance by a module included later, keep the visibility they were defined with there. ## Mixing the forms in one class The forms combine freely, and the order of lines matters: 1. A bare `private` changes the default for what follows; it does not touch methods already defined above it. 2. `private :name` changes one method and leaves the default alone, so the definitions after it keep whatever section they are in. 3. `public :name` below a `private` section makes that one method public again without ending the section. Reading a class, the reliable way to know a method's visibility is to find the most recent line that set it: a named modifier after the definition, or otherwise the section the `def` sits in. ## Picking a style Both forms are idiomatic. A common convention is a single `private` section near the bottom of the class, so readers can see at a glance where the public interface ends. The symbol-list form is clearer when only one or two methods change, or when visibility must change for a method defined elsewhere.

  • In Ruby, why does private placed above def self.build not make build private?
    `def self.build` defines a singleton method on the class object, and Ruby defines singleton methods as public regardless of the section's default visibility. To hide it, call `private_class_method :build` after the definition.
  • In Ruby, how do you make a public method inherited from a parent class private in a subclass?
    Call `private :method_name` in the subclass body. The symbol form works on methods found in ancestors too; it records a private entry in the subclass, so the parent keeps its public method while instances of the subclass treat it as private.

saying these in an interview costs you the question

  • A bare private makes def self.x class methods private too
  • private :audit may appear before def audit
  • A private section carries over into a reopened class body
  • private attr_reader :x raises on Ruby 4.0
  • private with no arguments returns the list of private methods