インスタンス変数とかはselfに依存するという話

@varが何を指すかって、何を元に判断しているのだろうか。

前提

ローカル変数

「ローカル変数のスコープは、宣言した位置からその変数が宣言されたブロック、メソッド定義、またはクラス/モジュール定義の終りまでです。」*1

class Sample
  var = 1
end

class Sample
  p var  # => undefined local variable or method `var'
end

インスタンス変数

インスタンス変数は特定のオブジェクトに属している。

(オブジェクトは変数やメソッドを束ねたもの、と考えてよさそう。)

class Sample
  @var = 2
end

class Sample
  p @var  # => 2
end

本題

「定数やクラス変数、インスタンス変数、グローバル変数は...(中略)...selfを通じて間接的にアクセスされる。」*2

サンプルコードを仕切り直して、まず下準備。

class Sample
  # `Sample`というClassのインスタンスに@varをもたせる
  @var = "in Sample"

  def initialize
    # `sample`というSampleのインスタンスに@varをもたせる
    @var = "in an instance of Sample"
  end
end

sample = Sample.new

class << Sample
  # `Sampleの特異クラス`というClassのインスタンスに@varをもたせる
  @var = "in singleton class of Sample"
end

class << sample
  # `sampleの特異クラス`というClassのインスタンスに@varをもたせる
  @var = "in singleton class of sample"
end

x_evalメソッドをつかって、いつどの@varが呼ばれるのかをみてみる。

(x_evalしたときのコンテクストについてはこちらでまとめた。)

Sample.class_eval do
  # self: Sample
  # klass: Sample
  p @var  # => "in Sample"
end

Sample.instance_eval do
  # self: Sample
  # klass: Sampleの特異クラス
  p @var  # => "in Sample"
end

sample.instance_eval do
  # self: sample
  # klass: sampleの特異クラス
  p @var  # => "in an instance of Sample"
end

@varとして呼ばれるのは、その時点でselfによって指し示されるオブジェクトがもつ@varであることが分かった。

雑感

ここ数日evalとかについて考えていたら、Rubyにおいてコードは一見とても立体的に見えるけれど、つまるところ起きているのは単なるプロセスたちの実行で、それをさも「オブジェクトにメッセージを送っている」とか「クラスの中にいる」とか、イリュージョンのように仕立てているだけなのだなあ…と感じた。