ジェネリクスを実装するには

ジェネリクスとは何か、ということをちょっと考えていた。以下、頭の中の思考をそのまま引っ張り出した文章なので読みにくいかもしれないが勘弁してほしい。

メソッドのI/Oに対して、あるプレースホルダを置き、そのメソッドを使う側でそのプレースホルダの部分に対してのキャストを漏れなく行ったのだとしたら、それはジェネリクス足りうる。
このメソッドを使う場所を漏れなく、というのはアスペクト指向だから、アスペクト指向が実はジェネリクスの要件ではないかと着想した。

さて、単にメソッドのI/Oつまるところ、引数と戻り値の型だけ合わせればよいのであれば、さほど難しいわけではないが、JavaC#ジェネリクスはメソッドの集合であるクラスというものに対してジェネリクス型パラメータを与えることができる。
これは、ある種のメソッドの集合を考えて、プレースホルダが置け、アスペクト指向により該当箇所を網羅すれば済む。

さて、それらのメソッドの引数に関数ポインタが渡せたならばどうか。「コール側 ⇔ メソッド群」という関係から、「コール側 ⇔ メソッド群 ⇔ 関数ポインタによるコールバック」という関係になる。ここで、ジェネリクスによる型を置換するためにプレースホルダを抽象的に扱わなければいけないのは「メソッド群」の部分だけで、コール側とコールバック部分は具象型でプログラムすることが許される。

このようなキセル状のジェネリクスを考えるとしても、そもそもコールバック関数をどこかしらのメソッドのInで渡すのであれば、その部分のアスペクトで対応すればよいだけのこと。
問題となるのは、抽象メソッドとそれを実装する具象型との間でのプレースホルダの管理である。*1

ここで、アスペクトはメソッドのI/O、関数ポインタのI/Oの他に、継承階層での処理の委譲部分にもウィービングする必要があると言うことになる。

まとめる。

  • メソッド群を管理する単位を持てる*2
  • それらの引数にプレースホルダを置ける*3
  • メソッドのI/Oおよび継承での処理の委譲に対して、具象型へのキャストというアスペクトをウィービングできる

という条件下でジェネリクス指向を実装することができる。

Javaの場合

Javaの場合、メソッド群というのはクラスやインターフェースという型によって実装される。メソッド群のインスタンスはクラスのインスタンスが対応付く。

プレースホルダはまんまジェネリクス型パラメータだ。

ではアスペクトのウィービングはどうか?これはコンパイラによって為される。コンパイル時点で全てのメソッドI/O部分および継承での処理の委譲に対して、型のキャスト処理がウィービングされる。Javaではこの際にジェネリクスの型情報は消滅する。この型消去=イレイジャこそがキャストというアスペクトのウィービングだ。


要件を満たせる既存言語であればジェネリクス機能を付加することが可能なのではないだろうか。

*1:GoFのテンプレートメソッドパターンにジェネリクスを用いて、テンプレートの具象型では具象的な型でプログラミングできるように設計したものを想像してもらえればよい

*2:メソッドというよりはSmalltalk式にメッセージ送信とする方がより一般的に解釈できることだろう

*3:型のエイリアスのようなものでもよいだろうし、アノテーション的なものでもあるいは可能だろう