From: toyofuku@... Date: 1998-03-06T04:43:06+09:00 Subject: [ruby-list:6975] Re: coerce 豊福@パパイヤです。 メールの津波に押し流されてます。 けいじゅさん >> class Fixnum >> alias plus_exept_for_matrix + ... >> end >> >>というのはできませんか。 > > いや, できます. ただ, この方法をすべてのクラスがとると > 1. 複数のクラスでaliasするとわけがわからなくなる(まあ, coerceベースで > も十分そうですが) > 2. たぶん, 一番良く利用されるFixnum#+が遅くなる. > 3. 一番の問題が, aliasすべきクラスが多いのでcoerceで対応した方が楽, 私もそう思います。:-) > そうですね. そういう意味ではこのクラスがどのクラスとの演算(coerce)をサ > ポートしているか明確にしなくてはなりませんね. さらに, 相互の互換性はお > 互いに調整する必要がありますね. > # 今までは私しか作っていないので問題なかったんですが(^^;;; > ちなみに現在は: > (Fixnum->Bignum->Float) -> (Rational <-> Complex) -> (Matrix <-> Vector) > となっています. これはしょうがないのですかね。すべてのクラスに 平等にするには足し算のクラスでも作って class PlusOp def PlusOp.plus(x, y) x と y のタイプのすべての組み合せで場合分け してそれぞれの足し算を実行 # 新しいクラスを作ったらそれに関する足し算を # このメソッドに追加する end end の PlusOp.plus を呼ぶようにするくらいしか 思いつきません。 >> coerce という機構は ruby で初めて知ったのですが >>Smalltalk ではここらへんどういう態度をとっているの >>でしょうか。 > > もっと単純です. > 昔かいた本 ``オブジェクト指向プログラミング'', ascii, pp.277-282 の中 > にその記述があったのでそれをぬきだしますと:: 簡単なケースしか扱っていないのですね。 > ちなみにこの後, 他の技法である. > * ダブルディスパッチ > * マルチメソッド(CLOSとか) > の方法も簡単に説明してあります. 聞いてばかりですみませんが、もし簡単なこと でしたら教えて下さい。 > when Matrix > のあとは何も書いてないのでcaseをぬけてfail以下に進みます. Cだとbreakす > る必要があるのでwhen Matrix/elseは同じ処理をすることになるんですがruby > では違いますよね. C の case と混同していました。break がないから else の方に流れていくのでは?と。 >> 上の方法でも新しい型を作って実質そこにすべてまか >>せているようにバラエティあふれる演算に対して引数が >>other だけの coerce に協力させるのはきびしいような >>気がするのですが。 > > 実際の話として, 数値的クラスってそんなに数はないと思いますし, 一般の人 > が作るものでもないので, とりあえず対応できるってことでも満足するべきか > な? と思っています. > まだ, 今なら本当に必要であるならば変更(のリクエスト)は可能であると思い > ますので検討の価値はあると思います. Scalarクラスを使う方法で気になるのは (1) coerce には演算の区別がないので一つの演算が Scalarクラスを使うことになると他のすべての 演算も Scalarクラスを使うことになる。もし別の 演算がさらに別のクラスを使いたくなると・・・ ==> coerce の引数にメソッドを追加してはどうか (2) 本当は Numericクラスあたりでやらしたいことを わざわざ Scalarクラスのオブジェクトを作って それにやらしている。 ==> 適用すべきメソッドを coerce の返値で教えて やってはどうか この方法で Matrix 関連を書くと次のようになります。 書き方はいい加減ですがやりたいことはわかって もらえると思います。 class Matrix def coerce(other, meth) case meth when :+ case other when Numeric エラー ... end when :* case other when Numeric return other, self, Numeric::* ... end ... end end end class Numeric def *(other) case other when Matrix return other.collect{|e| self * e} ... end end end class Fixnum def *(other) case other ... else x, y, meth = other.coerce(self, :*) if (meth) x.send(meth, y) else x * y end end end end ついでに matrix.rb での質問です。 Scalar::/ case other when Matrix self * _M.inverse の _M って何ですか。 Scalar::** case other when Matrix other.powered_by(self) の powered_by って何ですか。 ここはエラーにしそうなところですが。 まさか exp(M) を計算して返そうと・・・ --- 豊福@パパイヤ unbound@papaya.juice.or.jp toyofuku@juice.or.jp