Skip to content

@keithrbennett /class_vars.rb
Created

Embed URL

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Class Variables vs. Class Instance Variables
=begin
The "Class Variable" Method in class GuidProvider1 (the "@@" notation) is
simpler to use, but violates the principle that the object that owns a
variable is the only one who can directly read or modify it. That is, there
is no privacy or protection, in that there is no way the instances can be
prevented from reading and writing to the variable (for example, the 'next'
instance method does both).
In contrast, the "Class Instance Variable" single @ notation as shown in
GuidProvider2 behaves in a way that is consistent with instance variables in
other contexts (that is, within instance methods). The variables are not
readable directly, but instead must be explicitly exposed by providing a
class getter method. In the example, a getter but not a setter is
defined so that instances cannot directly modify the variable.
=end
# "Class Variable" Method
class GuidProvider1
@@highest_seqno = 0
def next
@@highest_seqno += 1
end
def self.highest_seqno
@@highest_seqno
end
end
guid_provider = GuidProvider1.new
50.times { guid_provider.next }
puts "Highest sequence number for GuidProvider1 is #{guid_provider.class.highest_seqno}"
# "Class Instance Variable" Method
class GuidProvider2
@highest_seqno = 0
class << self
attr_reader :highest_seqno
end
def self.next
@highest_seqno += 1
end
def next
self.class.next
end
end
guid_provider = GuidProvider2.new
5.times { guid_provider.next }
puts "Highest sequence number is #{GuidProvider2.highest_seqno}"
puts "Can't write to it, this will throw an error because we defined a getter but not a setter:"
guid_provider.highest_seqno = 3
@cflipse

Kieth, another thing to be aware of is that @@ variables are not protected; that is, there is only one variable for the entire class heirarchy, and subclasses can freely modify it:

class Foo                                                                          
  @@foo = 1                                                                        
  def foo                                                                          
    @@foo                                                                          
  end                                                                              
end                                                                                

class FooBar < Foo                                                                 
  def next                                                                         
    @@foo += 1                                                                     
  end                                                                              
end                                                                                

FooBar.new.next                                                                    
puts Foo.new.foo  # => 2

This is bad because it ignores any invariants that might be required for the parent class to behave correctly, and errors of this sort can be very hard to track down. @@class_variables have been on the "deprecated, avoid this" list for a long, long time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.