Search code examples
rubyclass-variables

Confusion about ruby class variable


Assume a simple ruby program using a class variable,

    class Holder
      @@var = 99
      def Holder.var=(val)
        @@var = val
      end
      def var
        @@var
      end
    end

    @@var = "top level variable"

    a = Holder.new
    puts a.var

I guess the result should be 99, but the output is not 99. I wonder why. Since class variable's scope is the class, I assume the line @@var = "top level variable" would not affect the variable in the class.


Solution

  • @@var is a class variable of Holder. And the @@var at the top level is not the same class variable of same name @@var of Holder, it is you are creating a brand new class variable for the class Object. Now @@var is shared with the subclass(es) of the parent class. Object is a parent class of the class Holder. In Ruby, if you don't explicitly define a super class of any custom class, you are defining using class keyword, then Object class becomes the default super class of the class, you just created.

    On top level, you are defining a new class variable in the class Object, like you did, in your posted example. As through inheritance, it is now available to the class Holder.

    I mean, when you wrote the below :

    class Holder
      @@var = 99
      def Holder.var=(val)
        @@var = val
      end
      def var
        @@var
      end
    end
    

    @@var is not added already to the Object class. Now on the top-level when you wrote the below line :

    @@var = "top level variable"
    

    It means, you are adding it to Object class and also updating old variable(@@var) same name as in the Holder class one, with this new one, you just defined in the scope of Object class.

    Remember, class variables are shared variables and visible only to the class(B), where you defined it and its descendant class(C), descendant(D) of the descendant class(C), so on. But not visible by the super-class( A as below ) of the class( B as below ), until you defined a same name variable in the parent class(A), as you are having in the child class(B).

    class A 
    end
    
    class B < A
      @@var = 10 
    end
    
    class C < B 
    end
    
    class D < C 
    end
    
    A.class_variable_get(:@@var) # uninitialized class variable @@var in A (NameError)
    B.class_variable_get(:@@var) # 10
    C.class_variable_get(:@@var) # 10
    D.class_variable_get(:@@var) # 10