Gauche > Archives > 2012/07/18

2012/07/18 04:04:26 UTCnatsutan
#
Gaucheのclassシステムについて教えてください。C++やJavaのコンストラクタのように、引数によって初期化方法を変えるようなコンストラクタは定義出来ないのでしょうか。具体的には、二次元空間の直線を表す<line>が、内部でax+by+c=0で表されるa,b,cのスロットで実装しているとします。この<line>を、2つの点の組や、一つの点と傾き等で初期化を行いたいです。
2012/07/18 04:17:37 UTCshiro
#
いくつか方法があります。一つはラッパー関数を噛ます方法。<line>はスロットa,b,cを持つようにしておくんですが、(make-line-from-coeff a b c)とか(make-line-from-points p0 p1)とかの手続きを定義してそっちをexportする。これらの手続きの中で(make <line> :a ... ) などのようにインスタンスを生成する。lineの場合はこちらが推奨ですね。そもそも「インスタンスを作る方法が複数ある場合、それをコンストラクタをオーバロードすることで表現する」という考え方自体がCLOSとあまり馴染まないです。
2012/07/18 04:19:38 UTCnatsutan
#
なるほど。(make-line-from・・・)でやってみます。
2012/07/18 04:19:47 UTCshiro
#
とはいえ、<line>にあたるものに継承関係があって、実際に作られるクラスが手続きが呼ばれるまでわからない場合はどうするか。Gaucheではクラスもファーストクラスオブジェクトですから、クラス自体を受けとるようにしてやる手があります。(make-line-from-points <line> p0 p1) とか (make-line-from-points <dotted-line> p0 p1) などと呼んでやる。
2012/07/18 04:20:31 UTCnatsutan
#
ふむふむ
2012/07/18 04:21:47 UTCshiro
#
さらに話が複雑になった場合、<line>族を束ねるメタクラス <line-meta> 等を作っておいて、make-from-pointsを<line-meta>に特化したメソッドにしておいてやると、同じインタフェースでクラスによって呼ばれるコンストラクタが違う、みたいなことが実現できます。
#
もう一つ、これはlineにはふさわしくないんですが、例えば自前で作った複素数インスタンスをデカルト座標形式と極座標形式で扱いたい、なんて場合に、スロットx, y, r, θを作っといてどちらかふたつを
#
virtual slotにしておく、という手もあります。そうすると (make <my-complex> :x x :y y) でも (make <my-complex> :r r :θ θ) でもコンストラクトできて、読み出しも(x,y)と(r,θ)どちらでも可能になります。同じものの見方が複数ある場合にはふさわしいかもしれません。
#
C++でも、「コンストラクタをオーバーロードする」という手は、「作りたい方法のいくつかが引数の数と型で区別できる」って場合にしか使えないですね。[
#
「傾きと切片」「x軸上の切片とy軸上の切片」の二つの方法でlineを作りたい場合は結局名前を変えるしかない。
2012/07/18 04:27:44 UTCnatsutan
#
その状況はありそうですね。>デカルト座標形式と極座標形式で扱いたい
#
すいません。上に出てきた「特化したメソッド」というのは、Common Lisp のdefmethodのイメージであってるでしょうか。
2012/07/18 04:29:31 UTCshiro
#
そうです。specializeの和訳のつもり。
2012/07/18 04:29:42 UTCnatsutan
#
わかりました。ありがとうございます。
2012/07/18 04:37:55 UTCとおる。
#
C++ だと無理矢理傾きっていうクラスを作るとかもできますね。make-line-from-slope-and-intercept に対応するものとして、Line(Slope(dx/dy), y) みたいな呼び出し方で。これはこれで分かりやすくていい気がするんですけど、どうですかね?
2012/07/18 04:39:54 UTCshiro
#
型でがちがちにする方向ならそれなんだけど、そういうふうに静的に攻めようとするとC++の型のサポートは弱い気がするんだよなあ。
2012/07/18 04:41:54 UTCとおる。
#
たしかに、途中からだんだん疲れてくるかも。あと、C++ はコンストラクタの初期化リストに書ける内容が決まってるので、RAII にそってつくろうとすると、そこから逃げられないっていうのもあるんですよねぇ。
#
IRA とか RIAA とかがいつもごっちゃになる。
2012/07/18 04:47:43 UTCshiro
#
静的型でもHaskellとかだとコンストラクタでごちゃごちゃやれないから fromSlopeAndIntercept Num Num -> Line とか fromIntercepts Num Num -> Line とか個別に関数作るんだと思う。Gaucheのオブジェクトシステムもそういうもんだと思えば。
2012/07/18 05:13:11 UTCyamasushi
#
線を作るには点が必要なのだから、点オブジェクトのメソッドとして実装するという道もあるように思いました。
#
点をどのように表現するかという問題もあるのでしょうけれど。
2012/07/18 05:26:49 UTCshiro
#
まあ、その点や線で何を作るかによるんじゃないでしょうか。応用とは独立した正解は無さそうな。