k-tokitoh

2019-08-05

インスタンス変数とかは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

本題

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

*1:https://docs.ruby-lang.org/ja/latest/doc/spec=2fvariables.html

*2:https://blog.yugui.jp/entry/547