Smalltalkのtは小文字です

id:sumim:about

オブジェクト指向の“モヤッと”の正体を知りたくなったら、id:sumim:20080415:p1id:sumim:20040525:p1 がお役に立つかも…。


 | 

2008-01-11

[] id:m-hiyama:20080109:1199863428Ruby


せっかくなので Ruby(1.9)についても調べてみました。結論から書くと、Ruby も Smalltalk と同じく四階建てで、その造りもそっくりでした。この絵が網羅している範囲に限れば、両者はほぼ“瓜二つ”。


http://squab.no-ip.com/collab/uploads/61/metaruby.png


ただ、隠し事をしない Smalltalk と違って、何もかもさらけ出してしまうことを必ずしも佳しとしない Ruby では、表面上は三階建てのフリをしている and/or 特異クラスが不可視化されているせいで、上図のような実情どおりにはユーザーには見えません。ちなみにどんな“フリ”をしているかは次図に。


http://squab.no-ip.com/collab/uploads/61/metarubypseudo.png


前後しますが、Ruby には「特異クラス」という、オブジェクト特異的な通常は不可視の無名クラスをアドホックに作れる(つまり元のオブジェクトはそれまでのクラスのもとを離れ、新しく作られた特異クラスのインスタンスとなる…)機構があり、これをインスタンス特異的なメソッド(Ruby ローカルな用語では「特異メソッド」)の裏方として機能させています。また、この特異クラスをクラスオブジェクトにも用いることで Smalltalk 的なメタクラスも実現しています。


しかしこの特異クラスへのアクセスは、Smalltalk のメタクラスのように簡単にはいきません。もちろん、Smalltalk 同様 Ruby にもオブジェクトの属するクラスを返す #class というメソッドはあるのですが、このメソッドでは、あるオブジェクトが特異クラスに属していたとしても、ユーザーはその事実を知ることができないのです。なぜなら、特異クラスに属するオブジェクトは、もともと通常のクラスに属していたオブジェクトであれば特異クラスを作る前に属していたもとのクラスに属し続けているかのように、クラスオブジェクトであれば Class に属しているかのように、それぞれが振る舞うからです。


obj = Object.new
obj.class      #=> Object

class << obj; def hoge; end end
obj.class      #=> Object
Object.class   #=> Class

そんなわけで、特異クラスにアクセスするのには、継承ツリーのトップに近いクラスかモジュールに次のようなメソッドを定義する必要があります。


def uniclass
  class << self
    self
  end
end

この #uniclass メソッドは、レシーバの特異クラスがあればそれを返し、無ければ新しく定義して返してきます(特異クラスがなければ nil を返すメソッドを定義できればよかったのですが、あいにく現在の Ruby ではそういうことはできないようです)。


obj.class         #=> Object
obj.uniclass      #=> #<Class:#<Object:0x548170>>
Object.class      #=> Class
Object.uniclass   #=> #<Class:Object>

以上をふまえて、各関係を確認するためのスクリプトは以下に。


class BasicObject; def uniclass; class << self; self end end end
class Person; def initialize(name); @name = name end end

s1 = "Hello"
s2 = "Bye-bye"
p = Person.new('tonkichi')

String.superclass                               #=> Object   /*  1 */
String.uniclass.superclass == Object.uniclass   #=> true
Person.superclass                               #=> Object   /*  2 */
Person.uniclass.superclass == Object.uniclass   #=> true
Class < Object                                  #=> true     /*  3 */
Class.uniclass < Object.uniclass                #=> true
Class.uniclass < Object                         #=> true
s1.class                                        #=> String   /*  4 */
s2.class                                        #=> String   /*  5 */
p.class                                         #=> Person   /*  6 */
String.uniclass                       #=> #<Class:String>    /*  7 */
String.uniclass.uniclass              #=> Class
Person.uniclass                       #=> #<Class:Person>    /*  8 */
Person.uniclass.uniclass              #=> Class
Object.uniclass                       #=> #<Class:Object>    /*  9 */
Object.uniclass.uniclass              #=> Class
Class.uniclass                        #=> #<Class:Class>     /* 10 */
Class.uniclass.uniclass               #=> Class

jmukjmuk 2008/01/15 03:14 ふと思いついて調べてみたのですが、 Ruby には Object#singleton_methods なるメソッドがありました。これが [] (空配列)を返すときは特異メソッドは定義されていないため、一般的には特異クラスは存在しないと考えられます。
ということを踏まえて、 uniclass メソッドで self.singleton_methods.empty? というチェックを入れると「なければnilを返す」処理のようなことができます。

sumimsumim 2008/01/15 13:10 それは良い手ですね。気づきませんでした! 以後使わせていただきます。ありがとうございます。

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト

コメントを書くには、なぞなぞ認証に回答する必要があります。

 | 
2004 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2005 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2006 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2007 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2008 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 12 |
2009 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2010 | 01 | 02 | 03 | 04 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2011 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2012 | 01 | 02 | 03 | 04 | 05 | 06 | 08 | 10 | 12 |
2013 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 11 | 12 |
2014 | 01 | 02 |

最近のコメント

1. 08/07 sumim
2. 08/07 squeaker
3. 06/26 squeaker
4. 06/26 sumim
5. 06/26 infoarchitect

最近のトラックバック

1. 01/30 no_orz_no_life - Erlangとジャンケン
2. 12/31 檜山正幸のキマイラ飼育記 - J言語、だってぇー?
3. 09/04 Twitter / @atsushifx
4. 07/06 みねこあ - オブジェクト指向 と FizzBuzz
5. 08/07 大島芳樹のカリフォルニア日記 - ランダムな文字列の中に隠された...

この日記のはてなブックマーク数
1260957