2009年1月10日土曜日

クラスとか

こんにちは。モリモルです。

Rubyのクラスについて頭の中のイメージを図にしてみました。
これで良いのかな?間違ってるかもしれません。。


Objectクラス
Objectクラスはすべてのクラスのスーパークラスです。
Class#superclassでさかのぼって行くとObjectクラスにたどり着きます。

irb(main):251:0* String.superclass
=> Object
irb(main):252:0> Class.superclass.superclass
=> Object
irb(main):254:0> Fixnum.superclass.superclass.superclass
=> Object


ObjectクラスにClass#superclassをするとnilが返ってきます。

irb(main):261:0* Object.superclass
=> nil


Classクラス
Classクラスは「クラスのクラスです」
この「クラスのクラス」といのがイメージしにくいですよね。。

「クラスがクラスを持つ」ということは、Rubyではクラスもオブジェクトということになるようです。

irb(main):303:0* String.class
=> Class
irb(main):304:0> String.object_id
=> -605238788


つまり、SringクラスはClassクラスのインスタンスということになります。
Classクラスに定義されたClass#superclassインスタンスメソッドをSringをレシーバーとして使えるわけですよね。

Classクラスもオブジェクトで、そのクラスは自身を指しているようです。
なので、Classをレシーバーとしてsuperclassメソッドが使えるということかな。

irb(main):289:0* Class.class
=> Class
irb(main):290:0> Class.superclass
=> Module



Class#superclass

ごくごく当然なのですが、"abc"だったり、KernelをレシーバーにするとClass#superclassには辿り着けないようです。クラスじゃないからスーパークラスを返せないというより、そのメソッドにたどり着けないということですよね。


irb(main):318:0* "abc".superlcass
NoMethodError: undefined method `superlcass' for "abc":String
from (irb):318
from :0
irb(main):319:0>
irb(main):320:0* Kernel.superclass
NoMethodError: undefined method `superclass' for Kernel:Module
from (irb):320
from :0
irb(main):321:0>



Module#ancestors

Moduleクラスに定義されたインスタンスメソッドは、すべてのモジュール&クラスをレシーバーにして使えるようです。
Moduleがレシーバの場合はClass経由でグルっと回って使えるというイメージなのかな。

irb(main):349:0* Module.ancestors
=> [Module, Object, Kernel]


"abc"からはたどり着けないようです。

irb(main):368:0* "abc".ancestors
NoMethodError: undefined method `ancestors' for "abc":String
from (irb):368
from :0



Objectクラスのインスタンスメソッド
Object#object_id、Object#class、Object#instance_of?、Object#kind_of? とか。


Objectクラスのインスタンスメソッドはすべてのオブジェクトをレシーバーとして使えるようです。


irb(main):358:0* "abc".object_id
=> -605469638
irb(main):359:0> Object.object_id
=> -605233518
irb(main):360:0> Kernel.object_id
=> -605233578