liveBook · Manning

Static field

As explained in The Well-Grounded Rubyist, Fourth Edition

A class variable is a Ruby variable whose information is shared per class hierarchy and whose name begins with two at-signs.

One counter across a hierarchy

class Car @@count = 0 def self.count @@count end def initialize @@count += 1 end end class Hybrid < Car end Car.new Hybrid.new Car.count # => 2 Hybrid.count # => 2 The class method reads the same counter that the instance method changes. The subclass shares it too. section 5.2.5

A Ruby class variable starts with two at-signs, as in @@count. It stores information for a class hierarchy, not separately for each instance. Its name distinguishes it from an instance variable such as @count, which belongs to one object. section 1.1.3 section 5.2.5

“Class variable” can be a misleading name: a subclass can affect a value seen through its parent. For example, setting @@value to 100 in Parent and then to 200 in Child makes a later read from Parent return 200. This matters when a counter intended for one class must stay independent of subclass counters. section 5.2.5

Choose storage according to who must share the value:

  • Use a class variable when the class, its instances, and its hierarchy need shared state, such as registered makes and counts. section 5.2.5
  • Use an instance variable on the class object when subclasses need separate totals. A class-level reader and writer can manage @total_count, while an instance updates self.class.total_count. section 5.2.5
Listing 5.6 Keeping track of car manufacturing statistics with class variables
class Car
  @@makes = []        1
  @@cars = {}         1
  @@total_count = 0   1
  attr_reader :make           2
  def self.total_count           3
    @@total_count      
  end                  
  def self.add_make(make)          4
    unless @@makes.include?(make)
      @@makes << make
      @@cars[make] = 0
    end
  end
  def initialize(make)
    if @@makes.include?(make)
      puts "Creating a new #{make}!"
      @make = make 5
      @@cars[make] += 1       6
      @@total_count += 1
    else 
      raise "No such make: #{make}."      7
    end
  end
  def make_mates           8
    @@cars[self.make]
  end
end

A complete car tracker uses class variables for registered makes, per-make counts, and a total count. section 5.2.5

How The Well-Grounded Rubyist, Fourth Edition covers it

How deep it goes
Works through syntax, visibility, a counting implementation, inheritance behavior, and a class-instance-variable alternative; does not descend into runtime internals.
Examples
Tracks registered car makes and counts, then contrasts a shared subclass counter with a class-instance-variable counter.
What it assumes
Assumes familiarity with classes, instances, methods, and inheritance; introduces the double-at-sign identifier before working through its behavior.
What you can do after
Build it from scratch: implement shared class-hierarchy state and choose separate class-object state when subclass totals must differ.
How it connects
Connects class variables to scope, inheritance, instance variables, class methods, and class instance variables.

Also explained in

Compare how 7 books explain static field →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of The Well-Grounded Rubyist, Fourth Edition. The section links point to the parts of the book it draws on.