インターフェースアセンブリ

 基本的にオブジェクトはsetter以外は全て見えたほうがいい。テストの時にもいいし、Expression>のように実行時に別のことを行うようなことも出来る。ドメイン特化言語ではこれは出来ねばならない。たとえばエロゲーを作る物語言語であれば、早送り時には必要な処理以外無視したりできなきゃいけない。Funcは使わず、使うならExpression>を使わないといけない。普通に演算子オーバーロードすれば規定で遅延評価される整数クラスみたいなのは簡単に作れるからそうしたほうがよりいい。

 しかし誰にとっても丸見えでは都合が悪い。実装アセンブリとインターフェースアセンブリに分ける。テストや実行に使うアセンブリは実装アセンブリを参照することで全てを見るが、コンポーネントを普通に使う側はインターフェースアセンブリのみを参照し、実装は見ない。そのコンポーネントに必要なメンバだけをインターフェースごしに見る。こうすることで、簡単に実装を取りかえられるようになる。アセンブリを動的にロードするようにすれば、実行時に実処理をコンポーネントごと取り替えることも出来る。

  • ComponentAssembly
  • ComponentAssemblyInterface < ComponentAssembly

 <は参照するを意味する。ComponentAssemblyInterfaceは、ComponentAssemblyに必要な引数や戻り値のインターフェースなんかが定義されている。コンポーネントはインターフェースが絶対に必要なのでここまでは確定。

 インターフェースアセンブリを用いてコンポーネント化する場合、実装アセンブリにインターフェースを実装したクラスを渡す役割のアセンブリが必要になる。そいつは全部のアセンブリを参照しなくてはいけない。これを全能アセンブリと呼ぶ。

 で、コンポーネントを使う側のことを考える。二つ方法があるように思う。

  • UseComponentAssembly
  • ComponentAssemblyInterface < UseComponentAssembly

 UseComponentAssemblyがComponentAssemblyInterfaceを参照し、そこに定義されている引数のインターフェースを直接実装する。そうすれば全能アセンブリはすぐにコンポーネントに渡すことが出来る。

 しかしUseComponentAssembly自体をコンポーネントとしたい場合、ComponentAssemblyInterfaceへの参照が邪魔になり独立したコンポーネントとして存在できなくなる。コンポーネントとするためにはやはりインターフェースアセンブリとの分割が必要不可欠だ。UseComponentAssemblyをComponentAssembly2とComponentAssemblyInterface2に分割する。

  • ComponentAssembly
  • ComponentAssemblyInterface < ComponentAssembly
  • ComponentAssembly2
  • ComponentAssemblyInterface2 < ComponentAssembly2

 この場合全能アセンブリの仕事は、ComponentAssembly2の中身を見てComponentAssemblyInterface実装クラスに変換し、ComponentAssemblyに渡してやることだ。ここで一手間かけることで相互に独立したアセンブリにすることが出来るので、そんなに悪い手じゃないように思う。この変換を確実に行えるようにするために、全てのデータにpublic getが必要になる。

 ところでC#の限界として、interfaceでは演算子オーバーロードが出来ない。C#で言語内に特化言語を作る場合、interfaceアセンブリだけでは不十分だ。特化言語は基本的にこのようになる。

 特化言語ソースアセンブリでは、特化言語として可能なこと以外の全てが出来ちゃいけない。特化言語ソースアセンブリは特化言語文法アセンブリ以外を見ちゃいけない。それでもC#として可能なことは出来てしまうが、それが発生することを注意深く抑える必要がある。

 特化言語文法アセンブリは文法だけを定義し、各コンポーネントに実際の処理はお任せすることになる。各コンポーネントのインターフェースアセンブリを参照するか、全能アセンブリに変換してもらうかだ。

インターフェースアセンブリの具体的なところ

 引数、戻り値のインターフェース、これは確実に必要だ。

 そしてその引数を処理し戻り値を返すメソッドのインターフェースが必要だ。そのメソッドを持っているインターフェースを最外部インターフェースと呼ぼう。インターフェースアセンブリには引数、戻り値、最外部インターフェースが必要。

 そして最外部インターフェースを取ってくるインターフェースもいる。最外部インターフェースクリエイターと呼ぼう。

 実装アセンブリから最外部インターフェースクリエイターを実装したクラスを探す。アセンブリを動的ロードしたならここでリフレクションを用いる。最外部インターフェースクリエイターさえとってこれれば、あとは普通に静的呼び出しで全部処理できる。動的ロードを行わず、全能アセンブリが直接参照してるなら普通にやれば済む。