0

Looking for an explanation why in the following example in Module.class_eval block, class variables lookup does not work:

class MyClass
  @@myvar = 123
  def self.myvar_getter
    @@myvar
  end
end

class MyClass
  p "#{self}, #{self.object_id}, #{singleton_class.object_id}"
  # output: "MyClass, 21055520, 21055500"
  p myvar_getter  # class method lookup working
  # output: 123
  p @@myvar       # class variable lookup working
  # output: 123
end

MyClass.class_eval do
  p "#{self}, #{self.object_id}, #{singleton_class.object_id}"
  # output: "MyClass, 21055520, 21055500"
  p myvar_getter  # class method lookup working as expected
  # output: 123
  p @@myvar       # class variable lookup NOT working (why ?)
  # output: -- following exception --
  #   a.rb:47: warning: class variable access from toplevel
  #   a.rb:47:in `block in <main>': uninitialized class variable
  #   @@myvar in Object (NameError)
end

As you may see the scope seems to be identical, self is the same, class method :myvar_getter is found in both cases, but class variable @@myvar is unexpectedly looked up in Object class within class_eval block. Can anybody explain this behavior other than because ?

David Unric
  • 7,421
  • 1
  • 37
  • 65
  • 1
    I think the lesson here is that class variables almost never behave the way you want them to. If you're dead set on using them, you might find more consistent results by using `class_variable_get/set` explicitly on the class in question. – Iron Savior Jul 02 '14 at 20:49
  • @IronSavior Thanks for the comment. I'm aware of `class_variable_get/set` methods. I've even read great article of Yehuda Katz about [metaprogramming in Ruby](http://yehudakatz.com/2009/11/15/metaprogramming-in-ruby-its-all-about-the-self/) where are described nuances between scope, method resolution and method definition. But nothing explains issue from the question. Is there even another concept that differentiates variables lookup ? – David Unric Jul 02 '14 at 20:57
  • possible duplicate of [Accessing Ruby Class Variables with class\_eval and instance\_eval](http://stackoverflow.com/questions/3434884/accessing-ruby-class-variables-with-class-eval-and-instance-eval) – infused Jul 02 '14 at 21:04
  • I vaguely recall reading something where the behavior of class variables in certain cases was inconsistent between ruby 1.8 and 1.9 as well. There might be use cases for them, but people should generally prefer to use instance variables in the context of the class. (for the benefit of anyone who comes across this later) – Iron Savior Jul 02 '14 at 22:51

1 Answers1

1

I've had to experience some weak moment, as the answer is quite clear & obvious.

From the Module.class_eval documentation:

Evaluates the string or block in the context of mod, except that when a block is given, constant/class variable lookup is not affected. This can be used to add methods to a class. module_eval returns the result of evaluating its argument.

So if I would need directly access class variables from eval block (ie. without use of class variable getter/setter methods), I'd just pass the code as a string:

MyClass.class_eval <<-EOS
  p @@myvar       # class variable lookup is working from a string
  # output: 123  voila!
  EOS
David Unric
  • 7,421
  • 1
  • 37
  • 65