In message "[ruby-list:711] Re: ? for Object#extend"
on 96/10/02, 石塚圭樹 <keiju / shljapan.co.jp> writes:
|
|けいじゅ@SHLジャパンです.
|で, この問題に関わらず, extend/includeした時に初期化を行ないたい時があ
|ると思うので, extend/includeした時に実行される関数が定義できるようになっ
|ているとよいと思いませんか?
あると便利なような,ここまでextendを活用するのはやりすぎのよ
うな….悩ましい.
|あれ? そうなんですか?? ビルトインクラスがextendが可能になれば, モジュー
|ル側で定義されるインスタンス変数が定義されると思っていましたが??
ビルトインクラスのインスタンスは通常のオブジェクトと違う構造
を持っているのですが,そこにインスタンス変数を格納するための
スロットが無いんです.ですから,たとえばSortableの例ではイン
スタンス変数にアクセスしようとした時点で例外が発生します.
もちろん昔に戻しても良いのですが1ビルトインオブジェクト当た
り4バイトサイズが増加します.
|>a = [1,2,3]
|>Sortable.new(a) {|e1, e2| e2 <=> e1} # -> a == [3, 2, 1]
|
|>Sortable::newは新しいモジュール(Sortableをincludeしている)を
|>つくってそれでaをextendするわけです.
|>
|>うーん,ちょっと捻り過ぎのような気もする.
|
|これって, 何をやっているのか良く分からないのですが...
|
|Sortable.new(a) は:
|
| a.extend(Sortable)
| a.sort{...}
|
|を行なっているだけではないんですよね??
-- ここからevalで実装
module xxxxx
include Sortable
@cmp = lambda
end
-- ここまでevalで実装
a.extend xxxxx
a.sort!
をします.つまりextend毎に新しいモジュールをつくってしまうわ
けです.インスタンス変数はモジュール側で持つと.
|これだと, 初期化の件は解決していると思いますが, インスタンス変数の件は
|解決していないですよね?
というわけで,姑息ながら解決しています.
これはやり過ぎならば(今思い付いた別アイディア),
ReverseSortable = Sortable.new{|e1, e2| e2 <=> e1}
ReverseSortable.install a
とかかなあ(newは新しいモジュールを作る).これならインスタン
ス変数に関して仕様変更の必要は無いなあ.
# ここまで書いて来てSortableというよりもSortedのような気がし
# て来たなあ.
しかし,個々のインスタンス毎に性質を変えるっていうのことその
ものがやりすぎのような気もするなあ.もしかするとこういう場合
はwrapperを使うのかもしれませんね.
a = [1,5,3]
a = SortedWrapper.new(a){|e1, e2| e2 <=> e1}
a -> [5,3,1]
class SortedWrapper
def initialize(orig)
@cmp = lambda if defined? yield
@orig = orig
sort @orig
end
def method_missing(id, *args)
@orig.send id, *args
end
:
end
まあ,ここまで議論して来てビルトインクラスのextendと特異メソッ
ドの追加を禁止する必要性は無いと思うようになりましたので,こ
の件に関しては次回リリースで対応しましょう.
|Hashは key->value の組みですよね. 一方 Sortableはkeyがインスタンスに含
|まれる感じになっていますよね? Hashのように key->value とするクラス(例:
|Bin)を作れるといっただけです.
|
|class Bin
| include Sortable
| ...
|end
|
|b = Bin.new
|b[key] = value
| ...
実際には[key,value]を要素にするという意味ですね.やりたいこ
とは分かりました.でも,2分木とかトライを実装する時に[],[]=
だけを期待するインタフェースじゃ効率が悪そうな気が…(実際は
sizeも必要でしょうね).
まつもと ゆきひろ /:|)