http://www.kmc.gr.jp/~ohai/diary/?date=20051212#p01
あー、これです。まさにこれです。こういうのを書きたかったんですが Ruby で書く方法がよくわからなくて、 Io でやるかなーとか思ってたのでした。 ohaiさんが同じこと考えておられたということで私もそこまで外してなかったかなーという感でとても嬉しいです。
ただ、実は少しだけ私の妄想とは違いまして、 ohaiさんの実装ですとfeatureの数だけコンテナがあって、オブジェクトはそれらのうち一つ以上のコンテナに所属するわけですが、負荷を考えるとできれば一箇所にしたい…ということで、以下のようなものが私の妄想の実装です。
class ObjManager @@all_klasses = [] @@container = Hash.new{|h,k| h[k]=Array.new} def add(obj) obj.objs.push(obj) end def objs(*features) case features.size when 0 @@all_klasses when 1 @@container[features.first] else main, *subs = *features @@container[main].find_all{|obj| subs - obj.features == []} end.collect{|k| k.objs}.flatten end def ObjManager.add_container(klass) @@all_klasses << klass klass.features.each do |f| @@container[f] << klass end end end class ManagedObj class << self def def_features(*features) @features ||= [] @features.concat(features) @objs = Array.new ObjManager.add_container(self) end attr_reader :features, :objs end def features self.class.features end def objs self.class.objs end end # テスト class A < ManagedObj def_features :x, :y end class B < ManagedObj def_features :y, :z end mgr = ObjManager.new mgr.add A.new mgr.add B.new p mgr.objs p mgr.objs(:x) p mgr.objs(:y) p mgr.objs(:y, :z) p mgr.objs(:z, :x)
つまるところ、オブジェクトはクラスごとに存在している別々のコンテナに収まっていて、 ObjManager はおのおののクラスのコンテナを feature ごとに持っている、というか。あー文字で書くより今度絵で描いた方が良さそう。
あと、 ohaiさんもおっしゃっている自己消滅の問題と、 zinniaさんのおっしゃっているstate遷移の問題はまさに私もいつもどう書いたもんかと悩むわけですが(ほぼ同源に近い問題だと認識しています)、これは古き良きメモリプールと関数ポインタ挿し替えが解に違いない…とか勝手に思っているわけでして、つまり多態ステ、というか。もしくはvtbl書き換え。
で、このへんの話+fiberでなんかとても幸せプログラミングな予感がしているんですが、今回の Ruby の例で(というか前回いきなり Ruby を持ち出してきたことからしてそうなんですが) Ruby 程度に DSL 書ける言語じゃないと表現できないわけでして、となると専門言語だ、ということで Object Oriented はもう古くて Task Oriented Programming の時代です。
というのはまぁ実装してなくてよくわからんのでなんかやってみます…あと関数ポインタ挿し替えは Matzにっき で知った Objective-C のポージングでいけるんじゃないかとか妄想してるわけですが、全く調べてません。あと豆乳。