When you learn about objects, you usually learn that they can
capture two kinds of data: instance and class. Instance variables are the
most common case, the data varies with each instance of the object. Class
variables, often referred to as static variables, are shared across all
instances of a class. Every instance points to same value and any
changes are seen by all. Class variables are much less common than
instance variables, especially mutable class variables. A particular wrinkle with class variables is how they interact
with inheritance. Consider a class variable that's used to store
instances of itself. (If the ruby is unfamiliar see my reading guide.)
#ruby
class Employee
@@instances = []
def self.instances
return @@instances
end
def store
@@instances << self
end
def initialize name
@name = name
end
end
Employee.new('Martin').store
Employee.new('Roy').store
Employee.new('Erik').store
puts Employee.instances.size
No suprise here, there are three employees. But now try this.
#ruby
class Employee
@@instances = []
def self.instances
@@instances
end
def store
@@instances << self
end
def initialize name
@name = name
end
end
class Programmer < Employee; end
class Overhead < Employee; end
Overhead.new('Martin').store
Overhead.new('Roy').store
Programmer.new('Erik').store
puts Overhead.instances.size
puts Programmer.instances.size
The output here is 3 and 3, while we'd probably prefer 2 and 1. The
reason is that a class variable is shared across all
instances of a class, which includes all subclasses. There are two
classes but only one variable. Sometimes this variable across a hierarchy is exactly what we
want, but soemtimes, as in this case, we'd prefer a different
variable for each class. I first came across this concept in some later
versions of Smalltalk under the name of class instance variable. You
could refer to a class instance variable the same way as with a
class variable, but you got a different value per class. Support for class instance variables isn't common in OO
languages, but it's not too hard to it yourself. The obvious way is
to use a dictionary keyed by class name.
#ruby
class Employee
@@instances = {}
def self.instances
@@instances[self]
end
def store
@@instances[self.class] ||= []
@@instances[self.class] << self
end
def initialize name
@name = name
end
end
class Overhead < Employee; end
class Programmer < Employee; end
Overhead.new('Martin').store
Overhead.new('Roy').store
Programmer.new('Erik').store
puts Overhead.instances.size
puts Programmer.instances.size
You can use this technique in any OO language. Ruby, however,
actually has class instance variables. #ruby
class Employee
class << self; attr_accessor :instances; end
def store
self.class.instances ||= []
self.class.instances << self
end
def initialize name
@name = name
end
end
class Overhead < Employee; end
class Programmer < Employee; end
Overhead.new('Martin').store
Overhead.new('Roy').store
Programmer.new('Erik').store
puts Overhead.instances.size
puts Programmer.instances.size
The definition of the class instance variable is the fragment
class << self; attr_accessor :instances; end .
For reasons that I don't really want to go into, this defines an instance
variable (and getters and setters) on the class employee that's
inherited by its descendents. Unlike class variables these class
instance variables will take different values for each class object. Class instance variables are pretty rare, but useful when you do
need them.
|