ベクトル演算

を作ってみた。

加算は、演算後に次元が変わらないので、割と簡単。

template Dimension(T) {
    static if (!is (typeof(T.init[0]))) {
        const size_t Dimension = 0;
    } else {
        const size_t Dimension = 1 + Dimension!(typeof(T.init[0]));
    }
}

template ElementType(T) {
    static if (0 == Dimension!(T)) {
        alias T ElementType;
    } else {
        alias typeof(T.init[0]) ElementType;
    }
}

という、エイリアス定義のテンプレートを用意しておき、

T add(T)(in T lhs, in T rhs) {
    static if (0 == Dimension!(T)) {
        return lhs + rhs;
    } else {
        return vv_add!(ElementType!(T))(lhs, rhs);
    }
}

private T[] vv_add(T)(in T[] lhs, in T[] rhs)
    in {
        assert(lhs.length == rhs.length);
    }
    body {
        T[] result = new T[lhs.length];
        foreach (i; 0..lhs.length) {
            result[i] = add!(T)(lhs[i], rhs[i]);
        }
        return result;
    }

ですんでしまう。

乗算となると、次元数が変わるので大変。

まぁ、現実的には2次元配列までサポートできればよいでしょう。
理論的には3次元以上の配列もサポートしたいけど。

続きを読む

「のだめカンタービレ」

表題の漫画がすごい人気だそうである。

18巻の発売が近いが、その前に気がついたことをメモっておく。
(まぁどっかで書かれているだろうけど)

以下ハゲしくネタバレです。

意外に喫煙者が多い

千秋はもとより、シュトレーゼマン、のだめ父、祖父。(ハリセンも吸ってたか?)
エリーゼ、多賀谷彩子などの女性キャラもしっかり吸ってるし、三木清良も本作中唯一のベッドシーンでお吸いになっておられる。
非喫煙者なら自分の好きなキャラにタバコ吸わせたりしないだろうから、作者の二ノ宮知が子自身喫煙者なんだろか?

登場人物の血液型が異様に偏っている

キャラクターブックで血液型が判明している人物中、多賀谷彩子=A、奥山 真澄=AB以外全員がO型かB型である。
千秋、清良、ハリセンがO型なのは納得いくものがある。
B型は少し解りにくく、峰がO、黒木クンがAとか言われると納得しちゃいそう。

まぁ、O型の情熱とB型の面白さが物語りを牽引しているというところか。
ちなみに喫煙者はO型ばっかし。

千秋には友人がいない?

気がついてビックリしたのがこれ。
だってねぇ、あの峰でさえ「違う、断じて」と言われているわけですから。
パリ編でものだめがターニャ、フランク、ユンロン達と友人なのは、自他ともに認めるところだろうけど、千秋とはそうであるかどうかはあやしい。
友人かどうかは周りがどう見るかよりも本人たちの主観の方が重要だったりするし。

おそらく千秋は音楽的に「これは」と思わせる部分がない人物には興味がないのだろう。
とすると同年代で友人有資格者は清良、黒木クン辺りか。
キャラクターブックでも中学時代は友人がいず、噂だけをふりまいていたというエピソードが書かれてるし。ホントにこいつはのだめ達に会うまでどーいう学生生活を送っていたんだろうと思う。

まぁ現在も友人いない状態が続いているのかもですが、のだめと出会って以来千秋の周囲がニギヤカでなかったことはないわけですが。

のだめは一人で立ち直る

気がついて感心したのがこれ。
のだめがスランプとか絶不調とかになったのは、ニナ・ルッツ祭のオランウータンと、マラドーナピアノコンクールで失敗したのと、コンブァトに適応できそうになかったのとなどがあるわけですが、その都度誰の手も借りず、一人で立ち直って来ている。感心感心。

のだめは何故ルイが鬼門なのか

そんなの読んでりゃ解るでしょうがと言われそうですが、おバカでニブいので夢で気がつくまでワカらんかった。
よーするにのだめはルイに千秋との共演のチャンスをさらわれているわけですね。二度も。
なかんづくボレロのときは気の毒だったなぁ。ルイがチェレスタやることになったあと、二階観覧席で憮然としてたけど、あんな不快そうなのだめの表情ってピアノコンクールの帰り道以来ですな。

そーいや、千秋とのだめが共演したのって、モーツァルトのピアノ連弾にしても、三善家でのエルガーにしても非公式なもので、人前でやったのって実はまだなかったりするのだなぁ。

なんか最新の KISS 立ち読みしたけど、またぞろルイが……

峰パパの人気はすごい

ナニがスゴいって3位。それも黒木クンを押さえての3位だからすごい。
人気投票やったのは13巻発売当時だったそーで、その頃はパリ編に入って結構たち、峰パパが登場しなくなって久しく、かつ黒木クンが再登場して結構たっているその時期に黒木クンを押さえてとはやるなぁ。

まぁあんなふーになんでもしてくれる父親が欲しいってのが票に反映されたんでしょうが、1位の千秋も料理うまいし、のだめ読者は食い意地がはっているという解釈も成り立つか(笑)。



以上、気がついたのはこんなとこですね。

18巻の表紙はトライアングルだそーです。

Non Virtual Interface

「Exceptional C++ Style」を買って読んだ。
C++ In Depth シリーズはたまに読むが買ったのは久しぶり。

「Effective C++」の3版も出ていてこちらも欲しいのだが、2版とダブる項目多いだろうし、立ち読みしてみると、丁寧語で書かれていてユーモアの部分がカットされていたのは残念。

Exceptional の方は、敬語でなくユーモアたっぷりにやってる。よかよか。

項目としては

こういうふうにすれ

という項目より

これは使うな

という項目が目立つ。
曰く

export は「まだ」使うな
auto は使うな
register は使うな
inline は使うな
例外指定はするな

といった具合。
auto, register, inline はもともと全然使ってなかったし、日記に書くほど「ありがたい教え」というわけではない。

読んで真新しかったのがタイトルの Non Virtual Interface パターン。

どゆのかというといわゆる Starategy の抽象クラスが

class C {
public:
    virtual void Operation(T1 arg1, T2 arg2);
};

と定義されていたとすると、この公開仮想インターインターフェイスは2つの役割を果たしているという。

1. 使う人に使い方(インターフェイス)を提供している
2. 派生クラスに「こういうふうに上書いてください」とカスタマイズの規約を提供している

という具合に。

2つの違った対象に「同時に」働きを提供しているというのは具合が悪く、分離すべきだという。
例えばお客さんから「公開インターフェイスにもひとつパラメータ増やしてぇ」と言われても、カスタマイズしてくれてる派生クラスさん達に頭を下げねばならず、派生クラスさんから「あのパラメータはいらんくなったよ」と言われてもお客さんの手前、勝手にインターフェイスを変えるわけにもいかない。

で、分離の方法なんすが pimpl イディオムだの Bridge パターンだの Body-Handle イディオムだの封筒クラスだのを使う手もあるが、もっと簡単に

class C {
public:
    // 公開インターフェイス
    void Operation(T1 arg1, T2 arg2) {
        OperationProc1(arg1, arg2);
        OperationProc2()
    }
private:
    // カスタマイズ用インターフェイス
    virtual void OperationProc1(T1 arg1, T2 arg2);
    virtual void OperationProc2();
};

とでもやっておいて、派生クラスには private なメソッドを上書いてもらえばよい、というのが、NVI パターンだそーだ。

クラス図としては Template Method パターンと同じになるが、目的が違うので違う名前をつけたそーな。Herb Sutter さんのオリジナルかどーかは知らんが、WinFX の実装では継承トゥリーを作るときは殆どこのパターンが使われてるそーな。
(private なメソッドでも仮想にしてオーバーライドできるというのは初めて知った。なんか親クラスから子クラスの private メソッドをコールしてるようでできないような感じでいたのだが)

ところでこれ、C++以外の C#, Java, D 等で抽象クラスの部分に interface を使おうとしてもできない。interface は実装を持てないし、そもそも interface で提供する公開インターフェイスが前述の2つの役割

お客さん、こー使ってね
カスタマイザーさん、こーいうふうに実装してね

というのを提供するためのものだからだ。

何が言いたいかというと、この件に関しては interface を持たない C++ の不利が消えるのだ。

NVI の良さは解った。
が、別に Herb Sutter さんが、既存の Strategy パターンが悪いので使うな、と言っているわけではない。関数オブジェクトでアルゴリズムを渡すときなど、おおいにつかうべきであろう。

しかし既存の 23 パターンのうち、継承と多態を使っているもので、NVIパターンを併用した方がよいのもありそうである。

ちょっと考えてみた。

Bridge
  そもそもの目的が、インターフェイスと実装を分離する
  という NVI と共通のものだから、Implementor の
  継承部分にわざわざ NVI を混ぜることはない。

State
  状態(State)と、状態を持っているもの(Context)との
  結びつきが密接であり、Context を使用する側としては
  むしろ状態のことにとんちゃくしたくないためにこの
  パターンを使う。
  とすれば、State の公開インターフェイスを Context を
  使う人にわざわざみせる機会は少ないと思われる。
  言い方を変えれば State は Context の「実装の詳細」で
  あってもともとお客さんからは隠されているのでわざわざ
  NVI を使ってさらに隠すことはない

Prototype
  これも NVI 使わないでいーんじゃねーかなー。
  だってインターフェイスが決まりきってるもん。
  メソッド名を clone にするか duplicate にするか
  の違いくらいで、引数なし、戻り値の型も決まり
  きってるしぃ。

Composite
  これ。これです。NVIを併用すべきなのは。
  Component にできることと、Leaf や Composite が
  行う実装の詳細とは分離すべき

Decorator
  ワカらん。判断できん。
  Decorator は Component が提供するインターフェイス
  実装するが、その実装手段として内部に持っている
  Component を使うこともあるというややこしい関係。
  NVI を使うと、外部向け提供のインターフェイスは、
  Component のみが行い、Decorator は実装にのみ精を
  出すということになるか。

Visitor
  そもそも私はコイツが嫌い。
  ダブルディスパッチで Element と Visitor の
  両方の型の違いを吸収する仕組みは見事とは
  思うが、完全にプログラムの都合のためにのみ
  存在するパターン。大体 Visitor は型が特定
  されたあと Element の公開メソッドを
  呼び出すだけで自分ではなにもしない。
  型の特定が終われば用なしの存在。
  大体、現実に対応するモデルが存在しない。
  Element を「訪問」するものって一体ナニ?
  見せて。あるのなら。

  と言った不満は横道であり、Visitor は
  Element が「自分で持っている」機能を
  実現するための「実装の詳細」であり、
  もともとお客さんなどの外部からは隠されて
  いることが多いと思われる。お客さんが
  「機能」Visitor を生成して Element に
  向かって「これをやれ」といって投げつけ
  る姿はちょっと想像し難い。

意外と NVI を併用すべきパターンが見つからない。
Interpreter とか、Command など、まだ考えがおよんでいないのだが、使ったほうがよいかも知れない。

インスタンスメソッドのタプル化

構造体やクラスには tupleof プロパティがあるがこれは、フィールドつまりデータメンバに関してのみ取り出せる。しかし function や delegate も型であり値を持つわけだから、インスタンスメソッドや、static メソッドをタプル化することもできる筈である。

TypeInfo typeinfo(T) (T arg){
    return typeid(T);
}

class C {
    private {
        int       id_;
        char[]    name_;
    }

    const int    initial_id = 100;
    const char[] initial_name = "AAA";
    
    this(
        int       id     = initial_id,
        char[]    name = initial_name
    ) { id_ = id; name_ = name.dup; }

    char[] toString() { return house.string.toString(this.tupleof); }
    
    int    id() { return id_; }
    char[] name() { return name_.dup; }
}

void main() {
    auto cs = [
        new C(0, "A"),
        new C(1, "B"),
        new C(2, "C"),
    ];
    writefln(typeinfo(cs));
    writefln(cs);
}
...
doki.decorator.C[3]
[(0,A),(1,B),(2,C)]

とまぁ、このような簡単なクラスからメソッドを delegate として取出し、

    auto dgs = [
        tuple(&cs[0].id, &cs[0].name),
        tuple(&cs[1].id, &cs[1].name),
        tuple(&cs[2].id, &cs[2].name),
    ];
    writefln(typeinfo(dgs));

    foreach (dg; dgs) {
        writefln(typeinfo(dg));
        writefln(toString(dg.value[0](), dg.value[1]()));
    }
...
std.bind.Tuple!(int delegate(),char[] delegate()).Tuple[3]
std.bind.Tuple!(int delegate(),char[] delegate()).Tuple
(0,A)
std.bind.Tuple!(int delegate(),char[] delegate()).Tuple
(1,B)
std.bind.Tuple!(int delegate(),char[] delegate()).Tuple
(2,C)

タプル化したあと呼び出すというのは、割と簡単にできる。

クラスの外側からだとインスタンスを作ってからできるし、自動型推論も使えるので。

しかしこれ、tupleof プロパティよろしく、クラス自体にそういう機能をつけたいとこである。

class C {
    ...
    Tuple!(typeof(&typeof(this).init.id), typeof(&typeof(this).init.name))
        methods() {
            return tuple(&id, &name);
        }
}

void main() {
    auto dg = cs[0].methods();
    writefln(typeinfo(dg));
    writefln(toString(dg.value[0](), dg.value[1]()));
}
...
std.bind.Tuple!(int delegate(),char[] delegate()).Tuple
(0,A)

ご覧のように短い名前のメソッドがたった2つでかなり長いシグネチャーになってしまった。
メソッドボディの外側だと自動型推論が使えないし、this への参照がままならないので init プロパティに頼らなければいけなかったりするからである。

まぁ、シグネチャーの戻り値部分は事前に alias かけとくとして。

もうちょっとウマい方法ないかと考慮中。

とりあえずめでたい

Ver-1.00 リリースおめでとさんです。
でも、今後大きな仕様追加がされない思うとちと残念な気もする。

TIOBE Index | TIOBE - The Software Quality Companyとか見ると、いい線いってますな〜。
どんだけ C# にせまれるか。

PS. id:shinichiro_h さん、monooki どうも(去年の話)。

値オブジェクトのオーバーライド

え〜、まず CopyTuple の修正。

template CopyTuple(Values...) {
    void to(Types...)(inout Types lhs)
        in { static assert(Values.length <= lhs.length); }
        body { foreach (i, v; Values) lhs[i] = v; }
}

で、次に Object のオーバーライドについて。

Object のオーバーライド可能なメソッドは

    void print();
    char[] toString();
    hash_t toHash();
    int opCmp(Object o);
    int opEquals(Object o);

があるが、このうち下の3つはオブジェクト全体の値に関するものである。
で、構造体と class にせっかく tupleof プロパティがあるので、これを汎用的にオーバーライドできないかと考えた。

opEquals と opCmp はともかく toHash は、型汎用の関数テンプレートを作らないといかんかなぁと思っていたが、id:kurimura さんとこで、TypeInfo を使う方法があったので、割と簡単にできた。

自分自身との比較をしてないとか、連想配列メンバがあると期待した動作にならないとかいろいろあるでしょうが、とりあえず暫定版。

但しこれ、オブジェクトの値に関することだけにやたらと制約が多い。

まず、

オブジェクト全体を値として評価できるクラスでないとオーバーライドしても無意味

つまり、データメンバを持たないクラスをオーバーライドしてもしょうがないし、あっても static や const しかなかったらこれまた無意味。(final はどうか知らん?)
また Thread のように、インスタンスが違ったら別物と考えなければいけない class もーバーライドしてはいけない。
まさか Singleton にした class をオーバーライドする人もいないでしょうが……。

クラス継承階層内で複数回オーバーライドしてはいけない。

これは、equals の対称性が壊れるから。

親と子で比較するメンバの個数が違うと、等号の左辺に親と子のどちらかがくるかで結果が違ってしまう。a == b のとき、b == a が成り立たなくなるのだ。

連想配列メンバがあると期待した動作にならない。

連想配列はアドレスによる比較しかできないため。
もっとも連想配列は辞書として使うだろうから、内容の同じ連想配列を複数持つ意味は殆どない。(前に連想配列dup とか作ってしまったが)

だけど、連想配列は参照型なので、複数オブジェクトが同一の連想配列を共有するということはありえる。その場合はアドレスによる比較が行われ、期待した動作になる。

まぁ、ユーザーがメソッドを追加しない限り、データメンバがどーなろうとやることは一緒なのでラクになったっちうことで。

続きを読む