rubyclassvariablesinstance-eval

Accessing Ruby Class Variables with class_eval and instance_eval


I have the following:

class Test
    @@a = 10

    def show_a()
        puts "a: #{@@a}"
    end

    class << self
      @@b = '40'

      def show_b
        puts "b: #{@@b}"
    end
  end
end

Why does following work:

Test.instance_eval{show_b}
b: 40
=> nil

But I can't access @@b directly?

Test.instance_eval{ @@b }
NameError: uninitialized class variable @@b in Object

Likewise, the following works

t = Test.new
t.instance_eval{show_a}
a: 10
=> nil

but the following fails

t.instance_eval{ @@a }
NameError: uninitialized class variable @@a in Object

I don't understand why I can't access the Class Variables directly from the instance_eval blocks.


Solution

  • I just asked the same question to Matz during the RubyKaigi party. I was half-drunk, but he was perfectly sober, so you can take this as the definitive answer.

    Anton is right - the reason why you cannot access class variables through instance_eval() is "just because". Even class_eval() shares the same issue (Matz himself wasn't totally sure about class_eval() until I told him I'd already tried it). More specifically: scope-wise, class variables are more like constants than instance variables, so switching self (as instance_eval() and class_eval() do) is not going to make any difference when it comes to accessing them.

    In general, it might be a good idea to avoid class variables altogether.