定数の探索には2種類ある
- 継承チェーンを利用した探索
- レキシカルスコープチェーンを利用した探索
継承チェーンを利用した探索
動き
- クラス内を参照
- クラス内に参照するものがない場合には親クラスに参照しにいく
これを参照できる定数が見つかるまで繰り返します。
class ParentClass
CONSTANT = 'constant in ParentClass'
end
class ChildClass < ParentClass
p CONSTANT
end
上記のコードを例にして考えると、
- ChildClassクラスに定数の呼び出しがあるため、ChildClassクラス内を探索
- ChildClassクラスには定数がないので、親クラスのParentClassクラス内を探索
- そこに定数があったのでそれを参照
レキシカルスコープチェーンを利用した探索
レキシカルスコープはクラスや関数の定義時にスコープが決まる。
レキシカルスコープチェーンを理解するには以下の二つを押さえる必要があるらしい。
- nd_next
- nd_class
ndってなんの略だろう、、、
nd_nextとは
nd_nextは、親のレキシカルスコープを保持しているポインタ。通常のクラスを作成した場合は、トップレベルのスコープが保持される。
nd_classとは
nd_classは、スコープに対応するクラスやモジュールの情報を保持しているポインタ。
動き
- nd_classを利用してスコープに対応するクラスorモジュールを参照する
- クラスかモジュールが保持する定数テーブルに参照したい定数があるか確認する。
- 参照するものが見つからない場合は、nd_nextポインタを利用して親のレキシカルスコープに参照しに行く
参照できるものが見つかるまで上記を繰り返し行う。
module NameSpace
CONSTANT = 'constant in NameSpace'
class ParentClass
class ChildClass
p CONSTANT
end
end
end
上記のコードを例にして考えると、
- ChildClassクラスで定数の呼び出しが行われる。
- ChildClassクラスには定数がないので、一つネストを下げてParentClassクラスを探索する。
- そこにもないので、さらにネストを下げてNameSpaceモジュール内を探索する。
- そこに定数が定義されていたのでそれを参照する。
優先されるのは?
以上の二つで優先されるのは、レキシカルスコープチェーンを利用した探索である。
class ParentClass
CONSTANT = 'constant in ParentClass'
end
module NameSpace
CONSTANT = 'constant in NameSpace'
class ChildClass < ParentClass
p CONSTANT
end
end
上記のようなコードの場合、NameSpaceモジュール内に定義された定数が参照される。
NameSpaceモジュール内に定数が定義されていなかった場合、親クラスへ探索をしに行くため、ParentClassクラスに定義された定数が参照される。
まとめ
定数の参照では以下の二つの探索方法によって探索が行われる。
ただし、優先されるのはレキシカルスコープチェーンである。
- 継承チェーンを利用した探索
- レキシカルスコープチェーンを利用した探索
また、ここでは解説しなかったが、includeやprependによってMix-inされたモジュールの中に定義された定数は参照されることはない。