Ruby looks for class variable in the Object instead of specific class
Asked Answered
S

1

2

This part works:

 class Example1
   @@var1= "var1 in the Example1"
   def get_var1
     @@var1
   end
 end

 example1 = Example1.new
 example1.get_var1
 # => "var1 in the Example1"

but if I try eigenclass:

def example1.get_var1
  @@var1
end

example1.get_var1
# NameError: uninitialized class variable @@var1 in Object
# from (pry):128:in `get_var1'

Ruby looks @@var1 in the Object instead of the Example.

I have tested this code in the Ruby 1.9.3 and 2.0 with the same result.

Why does it happening?
The second thing, can we turn it off (so example.get_var1 won't look for class variables in the Object)?

Shawnee answered 1/7, 2014 at 12:59 Comment(3)
The official term is singleton class.Phocine
@Phocine Thank you, you are right, however eigenclass or metaclass is widely used in Ruby community and, as for tags, singleton is used for Singleton pattern. So, I don't see problems here.Catchpenny
True, but I think those terms are largely inventions from before Ruby 1.9, when Object#singleton_class was added. It pains me greatly how many people I see still using def metaclass; class << self; self; end; end when we've had a proper name and method for it for so long.Phocine
M
7

It appears as though the lexical scope for class variable lookup is kind of wacky. As near as I can tell, because you're not inside the

class Example1
end

block, ruby doesn't look up @@var in your class, but rather from Object. If you want it explicitly from your class, you can do:

def example1.get_var
    self.class.class_variable_get(:@@var1)
end

I stumbled across https://www.ruby-forum.com/topic/1228428 while searching for the answer. They're talking about 1.8.7, but it appears to apply to later versions as well.

Maleate answered 1/7, 2014 at 13:51 Comment(1)
I would agree. Singleton method definition is lexically scoped and the surrounding class is the Object in this example. This is the same behavior like class reopening. If you need access ancestor class variables directly just wrap the singleton definition inside parent class scope or use indirect class_variable_get as SomeGuy suggests.Cerellia

© 2022 - 2024 — McMap. All rights reserved.