2011年9月18日日曜日

型クラスとEclipse Adapter

まことに恥ずかしながら、ScalaとHaskellの型クラス(Type Class)を初めて知りました。
きっかけは、@kmizuさんのプレゼン「言語アップデート -Scala編-」で、@eed3si9nさんのアーティクル「Scala Implicits: 型クラス、襲来」で学びました。
初めて知った型クラスではありましたが、日頃Eclipseアプリケーションっを作っていて、近いことをやっていることに気づきました。

Eclipse Adapterは型クラスに近い
型クラスを学んですぐに感じたのは、これはEclipseのAdapters Extension Pointを使ってやっていることに近い、ということです。

上記サイトの例から、型クラス導入のモチベーションを整理します。
  1. モデルをLabelMakerインタフェースに適合させたい
  2. モデルをラップする形でアダプターを実装するとアイデンティティ問題が起こる
  3. 如何にモデルのアイデンティティを維持しつつ、インタフェース適合させるか
  4. 型によるアダプタインスタンスの選択を組み込む
このような、インタフェース適合と型によるアダプタ選択は、Eclipse Adapterの仕組みを彷彿とします。

Eclipseにおける型によるインタフェース適合
Eclipseアプリケーションを作っていると、再利用部分と拡張部分を粗結合にするために、アダプターを使用することが多くなります。Eclipseでは、このような時にインタフェースを適合する方法として2種類の方法があります。
  1. モデルがIAdaptableを実装し、getAdapter()がアダプタを返すよう実装する
  2. Adapters Extension Pointを利用する
1のIAdaptableによる方法は、モデルにインタフェースの実装を強要するので、どのようなモデルにでも使える方法ではありません。もっぱら、適合元オブジェクトがWorkbenchPartのような場合に使います。
2のAdapters Extension Pointによる方法は、IAdaptableを実装しないモデルに対してもインタフェースを適合させられます。適合元と適合先の組み合わせによってアダプタを生成するAdapterFactoryを実装して拡張ポイントにコントリビュートします。


Eclipse Adapter使用例
Eclipse Adapterを使ったコード例は以下のようになります。

void printLabel(Address address) {
ILabelProvider provider = (ILabelProvider)
Platform.getAdapterManager().getAdapter(address, ILbelProvider.class);
System.out.println(provider.getText(address));
}

上記のAdapterManagerの仕組みが、型クラスに期待する振る舞いに概ね対応します。Eclipseアプリケーションを作っていて、祖結合のために型クラスの必要性を感じたら、その時はAdaptes Extension Pointを使用すると良いでしょう。
なお、Eclipse Adapterのランタイムの振る舞いはExtension Object Patternここに詳しいです。


Eclipse Adapterと型クラスとの違い
Eclipse AdapterとScalaやHaskellの型クラスとは決定的に異なる部分があります。
  • Eclipse Adapterは実行時の仕組みであり、静的な型保証はできない。
  • Adapterルックアップのために、AdapterManager APIに依存してしまう。
実装言語がJavaであり、Eclipseアーキテクチャがとても古いことを考えると、致し方ないところでしょうか。
それでも、モデルの型によるアダプタの選択により、アイデンティティ問題の回避に期待通りの効果を発揮してくれます。


ともあれ、Eclipseアプリケーションの開発でEclips Adapterの仕組みを理解していたおかげで、ScalaやHaskellの型クラスについても、割とスムーズにイメージできました。
それにしても、HaskellやScalaの表現力はすごいですね。