少し前に書いたトップレベルでメソッドを定義したときの挙動が不思議 - (゚∀゚)o彡 sasata299's blogについて、id:faulistさんが詳しい解説記事を書いてくださいました。ありがとうございます!!

Rubyのトップレベルのメソッドの不思議 - As Sloth As Possible
"Object"はClassクラスの、"Kernel"はModuleクラスのインスタンスなんだけど、ClassクラスはModuleクラスの、ModuleクラスはObjectクラスのサブクラスになっている。つまり、上のコード中では"self"も"Object"も"Kernel"も、みんなObjectクラス(か、そのサブクラス)のインスタンスと言える。

「なるほどなるほど。」と思ったわけなのですが、少し不思議に感じたことがありました。それはRubyって全てのクラスの親クラスはObjectクラスであるはずなのに、Objectクラスの属するクラスを調べるとClassクラスであるということ。

p Object.class # Class

全てのクラスの親クラスであるはずのObjectクラスがClassクラスのインスタンスで、Classクラスの親クラス(の親クラス)がObjectクラス・・・??と混乱しそうですが、これが勘違いでした。実は↑のコードの中の Object はもちろんObjectクラスを表すものですが、あくまでもクラス名です。クラスそのものではなく、クラスへの参照を持っているだけです。

クラス名とクラス!?

Rubyのトップレベルのメソッドの不思議 - As Sloth As Possible
初めてのRubyを持ってる方は、8章のどこかにあるコラムを探してみて欲しい。小さい枠だけど、ちゃんと「クラス名とはClassクラスのインスタンスを作り、それを定数にしたもの」って話が書いてある。

クラス名というのは実は定数で(だから大文字から始まる名前じゃないといけない)、そのクラスを表すClassクラスのインスタンスへの参照を値として持つらしいです。つまり、あらゆるクラス名は実はインスタンスであり、属するクラスはClassクラスであるというわけです。

クラスの継承関係はこのようになっています(もちろんObjectクラスは全てのクラスの親クラスです)が

Ruby継承関係

各クラス名はClassクラスとこのような関係になっています。全てClassクラスのインスタンスです。自作のクラスだってそうです。図にするとこんな感じかな?

クラス名はClassクラスのインスタンス

ObjectやFixnumといったクラスを評価すると、to_sメソッドが暗黙的に呼ばれてクラス名を返す(多分)のでわかりにくいですが、実際には #<Class:0xb7b8439c> ←こんな感じのデータなのだと思います。

例えばFixnumクラスのクラス名に対して、あなたはどのクラスのインスタンスですか?と尋ねると「Classクラスです」と返ってきて、あなたのクラスの親クラスは何ですか?と尋ねると「Integerクラスです」と返ってくるわけです。これぞオブジェクト指向!!

p Fixnum.class      # Class
p Fixnum.superclass # Integer

で、トップレベルでメソッドを定義したときの挙動が不思議 - (゚∀゚)o彡 sasata299's blogの話に戻るわけですが、トップレベルにメソッドを定義すると、それはObjectクラスのインスタンスメソッドになります。さらに、ClassクラスはObjectクラスを親(の親)に持つため、Classクラスでも同じインスタンスメソッドが使えます。そして、Objectクラスへの参照を持つクラス名 Object はClassクラスのインスタンスであるため、main からも Object からも同じメソッドが呼べるようになる、というわけですね。なるほど〜。
このエントリーをはてなブックマークに追加