Bug #18927
closedCan't access class variable directly with class inheritance
Description
If a child class inherits from a parent class, and the child class sets a class variable, the parent class can't access the class variable literal:
class Parent
  def self.class_var
    puts @@class_var
  end
end
class Child < Parent
  @@class_var = "class_var"
end
Child.class_var
# => test.rb:3:in `class_var': uninitialized class variable @@class_var in Parent (NameError)
Confusingly, if we use class_variable_get (method lookup) to access @@class_var, we can access it as expected. We can alter the snippet from above to see this behavior:
class Parent
  def self.class_var
    puts class_variable_get(:@@class_var)
    puts @@class_var
  end
end
class Child < Parent
  @@class_var = "class_var"
end
Child.class_var
# => "class_var"
# => test.rb:4:in `class_var': uninitialized class variable @@class_var in Parent (NameError)
Is this desired behavior?¶
self is the subclass so it seems like the class variable should be looked up on the receiver. Why is the method lookup resolution different than the literal? Should it be different?
        
           Updated by jeremyevans0 (Jeremy Evans) over 3 years ago
          Updated by jeremyevans0 (Jeremy Evans) over 3 years ago
          
          
        
        
      
      Class variable lookup is different from instance variable and constant lookup, but it is more similar to constant lookup. It's based on the namespace/cref containing the access, not the receiver of the method containing the access (see vm_getclassvariable in vm_insnhelper.c).  Here's a modified example that works:
class Parent
end
class Child < Parent
  def Parent.class_var
    puts @@class_var
  end
end
class Child < Parent
  @@class_var = "class_var"
end
Child.class_var
The reason this works is that the @@class_var access is now in the Child namespace instead of the Parent namespace.
I don't think this is a bug, and based on previous issues, I believe @matz (Yukihiro Matsumoto) is no longer considering changes to class variable semantics. It's best to avoid using class variables completely in Ruby.
        
           Updated by mame (Yusuke Endoh) over 3 years ago
          Updated by mame (Yusuke Endoh) over 3 years ago
          
          
        
        
      
      - Status changed from Open to Rejected
Once a class variable is declared (initialized) in the lexical context of Child, it can only be accessed from the lexical context of Child and its subclasses. Otherwise, any class variable would be accessible from the context of Object, which is the same as a global variable.
It's best to avoid using class variables completely in Ruby.
Agreed.
        
           Updated by Eregon (Benoit Daloze) over 3 years ago
          Updated by Eregon (Benoit Daloze) over 3 years ago
          
          
        
        
      
      mame (Yusuke Endoh) wrote in #note-2:
It's best to avoid using class variables completely in Ruby.
Agreed.
Since we seem on the same page here, could we officially deprecate class variables?
Concretely I think it should be mentioned in the documentation, and maybe also a deprecation warning?
        
           Updated by Eregon (Benoit Daloze) over 3 years ago
          Updated by Eregon (Benoit Daloze) over 3 years ago
          
          
        
        
      
      I filed an issue for that: #18930