Permalink
Find file
Fetching contributors…
Cannot retrieve contributors at this time
153 lines (132 sloc) 3.76 KB

ss003: class variables belong to class hierarchies

I got the following from Metaprogramming Ruby discussion forum on Pragmatic BookShelf.

class Object
  @@v = 1
end

class MyClass
  @@v = 2
end

@@v  #=> 2

Paolo's explanation:
The reason why your example works the way it works is that class variables don't belong to classes (or objects in general) - they belong to class hierarchies. When you define @@v in Object, all the subclasses of Object (including MyClass) can see and modify @@v. All the instances of the subclasses of Object (including main) can also see and modify @@v, which is why you can also access @@v from the top level of your program.

Ken found this on page 338 of the latest Pickaxe book:
"Class variables are inherited across children but are unique across children."

The folowing is the output with Ruby 1.9.


irb(main):001:0> class Foo
irb(main):002:1>   @@var = "Foo" 
irb(main):003:1>   def self.get_var
irb(main):004:2>     @@var
irb(main):005:2>   end
irb(main):006:1> end
=> nil
irb(main):007:0> class Bar
irb(main):008:1>   @@var = "Bar" 
irb(main):009:1>   def self.get_var
irb(main):010:2>     @@var
irb(main):011:2>   end
irb(main):012:1> end
=> nil
irb(main):013:0> Foo.get_var
=> "Foo" 
irb(main):014:0> Bar.get_var
=> "Bar" 
irb(main):015:0> @@var
NameError: uninitialized class variable @@var in Object
    from (irb):15
    from /usr/bin/irb1.9:12:in `'
irb(main):016:0> Foo.class_variables
=> [:@@var]
irb(main):017:0> Bar.class_variables
=> [:@@var]
irb(main):018:0> Object.class_variables
=> []
irb(main):019:0> @@var = "top level" 
=> "top level" 
irb(main):020:0> @@var
=> "top level" 

irb(main):021:0> Foo.get_var
=> "top level" 
irb(main):022:0> Bar.get_var
=> "top level" 

irb(main):023:0> Foo.class_variables
=> []
irb(main):024:0> Bar.class_variables
=> []
irb(main):025:0> Object.class_variables
=> [:@@var]

Creating a class variable in a superclass actually reaches into subclasses and removes the class variable from the subclass!


Note:

The behavior of Ruby 1.8 and 1.9 are different.


C:\>ruby -v
ruby 1.8.6 (2007-09-24 patchlevel 111) [i386-mswin32]

C:\>irb
irb(main):001:0> class A
irb(main):002:1>   @@var = "A"
irb(main):003:1>   def self.get_var
irb(main):004:2>     @@var
irb(main):005:2>   end
irb(main):006:1> end
=> nil
irb(main):007:0> A.get_var
=> "A"
irb(main):008:0> @@var
NameError: uninitialized class variable @@var in Object
        from (irb):8
irb(main):009:0> @@var = 'top level'
=> "top level"
irb(main):010:0> @@var
=> "top level"
irb(main):011:0> A.get_var
=> "A"
irb(main):012:0> A.class_variables
=> ["@@var"]
irb(main):013:0> Object.class_variables
=> ["@@var"]
irb(main):014:0> class A
irb(main):015:1>   @@var = "AA"
irb(main):016:1> end
=> "AA"
irb(main):017:0> A.get_var
=> "AA"
irb(main):018:0> @@var
=> "top level"

The @@var of A or the @@var of Object looks like independent of each other. But, as I assign the @@var of Object at the first line:


C:\>irb
irb(main):001:0> @@var = 'top level'
=> "top level"
irb(main):002:0> class A
irb(main):003:1>   @@var = "A"
irb(main):004:1>   def self.get_var
irb(main):005:2>     @@var
irb(main):006:2>   end
irb(main):007:1> end
=> nil
irb(main):008:0> A.get_var
=> "A"
irb(main):009:0> @@var
=> "A"
irb(main):010:0> @@var = 'top level again'
=> "top level again"
irb(main):011:0> @@var
=> "top level again"
irb(main):012:0> A.get_var
=> "top level again"
irb(main):013:0> class A
irb(main):014:1>   @@var ="AA"
irb(main):015:1> end
=> "AA"
irb(main):016:0> A.get_var
=> "AA"
irb(main):017:0> @@var
=> "AA"

The @@var of A and the @@var of Object look like the same. This behavior made me crazy. I have to update Ruby asap. :-P