rubyのクラス変数

gold対策(模擬試験13)。  
インスタンス間で共有され、かつ自分自身のクラスとサブクラスで管理される。

class A
  @@x = 0
  class << self
    def x
      @@x
    end
  end
  def x
    @@x = 2
  end
end

class B < A
  @@x = 3
end
p A.x
# >> 3

これだけでも気持ち悪いのですが、 もっと気持ち悪い例がメタプログラミングRuby(4.1.4)で紹介されています。 ちょっと変更して掲載すると

@@v = 1 # !> class variable access from toplevel
class MyClass
  @@v = 2
  def v
    @@v
  end
end
@@v # => 2 # !> class variable access from toplevel
MyClass.new.v # => 2

@@v = 3 # !> class variable access from toplevel
MyClass.new.v # => 3

トップレベルで定義するとwarningが出ます。
こんな使い方はしないはずですが global変数のようです。
 

一応、global変数とは違う例を載せておきます。下記だとエラーとなります。

class MyClass
  @@v = 2
end
@@v # !> class variable access from toplevel
# ~> -:4:in `<main>': uninitialized class variable @@v in Object (NameError)

こんな動きになるのは、

クラス変数がクラスに属していないからだ。
クラスではなく、クラス階層に属しているのだ。
@@vはmainのコンテキストで定義されているので、mainのクラスであるObjectに属していることになる。
それから、Objectのすべての子孫にも属しているかだ。
結局はみんなが同じクラス変数を共有しているというわけだ。

なるほど。試してみます。

class MyClass
  @@v = 2
end
MyClass.class_variables
=> [:v]
>> Object.class_variables
=> []
@@v = 1
class MyClass; end
>> MyClass.class_variables
=> [:v]
>> Object.class_variables
=> [:v]

これは、恐ろしい。

多くのRubyistはクラス変数を使わずにクラスインスタンス変数を使っている。

使わないに越したことはないですね。