Class variables is a typical way to share state across instances of a class. Let’s say we have a Playlist class and we want to count how many instances of this class we have. We can write the following:
class Playlist @@number_of_playlists = 0 def initialize @@number_of_playlists += 1 end def play p "Playing..." end def get_number_of_playlists @@number_of_playlists end end
The problem comes when
we want to create subclasses of this class, e.g.
class HiphopPlaylist < Playlist @@number_of_playlists = 0 end class RockPlaylist < Playlist @@number_of_playlists = 0 end
And now let’s create some instances of these classes:
HiphopPlaylist.new RockPlaylist.new p RockPlaylist.new().get_number_of_playlists # It outputs 3, instead of 2
The problem is that the class variable that is created in the Playlist class is shared across the whole hierarchy. Since in Ruby the Class is also an Object, we can create instance variables that belong to the class object, and then create instance variable accessor.
class Playlist def initialize self.class.number_of_playlists +=1 end def self.number_of_playlists @number_of_playlists ||= 0 end def self.number_of_playlists=(n) @number_of_playlists = n end def get_number_of_playlists self.class.number_of_playlists end end class HiphopPlaylist < Playlist end class RockPlaylist < Playlist end
With that way our subclasses can calculate correctly the number of their playlists, since its of them has instance variable “number_of_playlists” on their object.
p HiphopPlaylist.new().get_number_of_playlists #1 RockPlaylist.new RockPlaylist.new p RockPlaylist.new().get_number_of_playlists #3