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






