よたらぼ
自分の興味の赴くままにIT技術系のネタを取りとめもなくメモっています。
Ruby言語やLinuxのネタが多いです。

August 18, 2002

[Ruby] Allocation Frameworkで悩む

Ruby-1.7系の場合、メソッドnewは allocate -> initializeという順番で初期化を行って行くんだけど、じゃぁ、いったいallocateでは何をしてinitializeでは何をすべきか、というところではまった。

具体的にはRuby/GTK2のGdk::Cursor用コード(の抜粋版)。

static VALUE gdkcursor_s_allocate(klass)
    VALUE klass;
{
    GdkCursor c;
    return Data_Make_Struct(klass, GdkColor, 0, free, c);
}
 
static VALUE
gdkcursor_initialize(argc, argv, self)
    int argc;
    VALUE *argv;
    VALUE self;
{
    VALUE source, mask, fg, bg, x, y;
    rb_scan_args(argc, argv, "15", &source, &mask, &fg, &bg, &x, &y);
    DATA_PTR(self) = gdk_cursor_new(NUM2INT(source));
    return self;
}

今のCVS版だと上記の(ような)実装になってるのだけど、これだと、allocateの方で生成したGdkColorが無駄になってしまう。

うーん、どうすれば良いんだ....と思ってruby-devの過去メールをあさると立石さんが同様の問題で悩まれていたようで、そのものずばりのスレッドがあった。ホント、読んでないよね<オレ。

で、この辺の情報ってどこかにまとまってないのかなぁ、と思いつつスレッドの内容をまとめてみた

Allocation Frameworkは「allocationのやり方がオブジェクトごとに異なっていて、どこにフックをかけたらよいのかわからない」という問題を解決するもの。 これにより、

  • Class.newでオブジェクトの生成。その中身は
  • Class.allocateでオブジェクトの生成(ただしinitializeされるまでは使用不能状態)
    「すべてのクラス」で「未初期化のRubyオブジェクト」を返すべき。
    allocateはごくまれに生成されるインスタンスのタイプや構造を知るためにも使われるので、できるだけなにもしない「空のRubyオブジェクト」を返したほうが良い。
  • obj.initializeでオブジェクトの初期化
    initializeはサブクラスでオーバーライドされる可能性がある
  • と統一されたので、生成と初期化について一貫性ができた。しかも、やや間接的ではあるが、クラスからそのクラスのインスタンスの「型」を知る方法ができたという副次的な効果もできた。

    T_DATAの場合にはptrを0としてData_Wrap_Structするのがよい。で、initializeで DATA_PTR(obj) = ptr と初期化する。 それ以外の「型」については個別に対応する必要があるが、「型」を自分で定義する機会は滅多に無いはず。

    ということは、T_DATAである上記コードは以下のように書けば良いのかな。

    static VALUE gdkcursor_s_allocate(klass)
        VALUE klass;
    {
        return Data_Wrap_Struct(klass, 0, free, 0);
    }
     
    initializeの方は同じ。
    

    んでもって

  • 立石さん
    また,allocateで使用不能なオブジェクトを作ったことで,すべてのメソッドでその使用不能状態を検出する作業が必要になるなどの場合があると思います.このような場合でもallocateで使用不能状態を作るべきかでちょっと悩んでしまいます.
  • なかださん
    これはinitializeする前だけでなく、たとえばcloseされたIOなんかにも当てはまる話です。Rubyが静的な(変数でなく)オブジェクトのスコープ(というよりライフスパンといったほうが適切?)を持たない以上、対応は必須だと思います。
  • まつもとさん
    ProcやThreadのように使用不能な状態の存在しないクラスもありますので、絶対にだめとは言えませんが、従っておいたほうがユーザに親切ではないだろうかとは思います。ProcやThreadも将来的には対応させようと思ってますし。
  • これって、あおきさんみたいにinitializeしていない場合はエラーを返すようにしないといけないということかな。となると上記のように単純にData_Wrap_Struct使うだけじゃダメだね....。

    とここまで考えてさかいさんのRuby/GLibのコードを読み直す

    gobj_holderが良い感じだ。そうか、こうすれば良いのか。さすがさかいさん...。

    それにしても

    まったく、ここまで何も理解してないでメンテナやってるオレもすごいな(^^;)。

    それからちょっと気になるけど

    この辺の仕組って変わっちゃったりするのかな、ちょっと心配。

    本日のツッコミ(全2件) [ツッコミを入れる]

    たむら [ブラボーな、まとめだと思われ。]

    むとぽん [自分の頭の中を整理したいときって、書かないとだめなんですよね〜、私の場合(^^;)。]


    August 18, 2004

    [Ruby-GNOME2] 続GnomeFiles

    今気づいたんだけど、Alexandria, Rabbitも登録してあるね。レッツボート!

    [Misc] ある業界人っぽい子供の名前

    近々子供が産まれるという人と、どんな名前がいいだろう?という話をしてたんだけど、ネットワークな仕事にちなんで、女の子だったら「静子(しすこ)」男の子だったら「留太(るーた)」が良いだろうということになった。

    もっとサーバよりに「蔵素太(くらすた)」とか言う案もでたが、「冗長構成取られても困る」と一蹴。

    やはりネットワークに戻って、「蘭(らん)」とか「歩人(ポート)」とか、双子の女の子だったら、「愛子(I子)」と「P子」はどうだろう、と言ったら、さすがに「P子」はないだろ、というお答え。他はアリなのか...(^^;)。

    いずれにせよ、今彼は名前探しに多少げんなりしているので、刷り込むなら今がチャンスだな(っておい(^^;))。

    オレに子供ができたらどうしよう。やはり「愚之夢(ぐのむ)」とか。いかん、それじゃー暴走族(古)だ。 


    August 18, 2005

    [Misc] お。安部さん復活ですね。

    陰ながら心配しておりました。ってか10kg減量って...うらやまぢぃ。


    更新 設定