Search code examples
rubyclass-variables

Ruby and class variables in inherit class


class A
  def set(v)
    @@v = v
  end
  def put
    puts @@v
  end
end

class B < A
end
class C < A
end

B.new.set 'b'
B.new.put # => b
C.new.set 'c'
C.new.put # => c
B.new.put # => c

Why? And how should I write this to have 'b' in last B.new.put?


Solution

  • Here is a nice article on the subject - Class and Instance Variables In Ruby.

    Basically, what you can do is:

    class A
      class << self
        attr_accessor :class_var
      end
    
      def set_class_var(value)
        self.class.class_var = value
      end
    
      def get_class_var
        self.class.class_var
      end
    end
    
    class B < A; end
    
    A.class_var = 'a'
    B.class_var = 'b'
    puts A.class_var # => a
    puts B.class_var # => b
    
    A.new.set_class_var 'aa'
    B.new.set_class_var 'bb'
    puts A.new.get_class_var # => aa
    puts B.new.get_class_var # => bb
    

    To understand it you should think about A as an instance of Class class (and that's how it is in Ruby). But every object in Ruby has its own singleton class that stores object-specific stuff like methods defined on object itself:

    a = A.new
    def a.foo
      puts 'foo'
    end
    

    In that case foo is method defined only for a object and not for every instance of A class. And another way to define method in object's singleton class is like that:

    class << a # open a's singleton class
      def bar  # define method that will be available only on 'a' object
        puts 'bar'
      end
    end
    

    In the first code snippet we use that approach to define class_var attribute accessor in the context of singleton class of our A class (it's a bit tricky, so you need to think about it). As the result class itself has class_var variable as well as its descendant class B. The difference is that every one of them has its own class_var variable that do not interfere.