インターフェースは無力なのが強いという結論

Rubyの機能にMix-inというのがあるらしい。
これは、多重継承を可能にする物だという。
多重継承とは1つのクラスが2つ以上のクラスを継承すること。
Java・C#では禁止されている。ただし、インターフェースという作るメソッド・プロパティを定義するだけのものは何個も実装できる。
すなわち、メソッドなどの内容を継承できるのはただ1つのクラスだけということ。
C#でIEnumerableインターフェースを実装する。けどそれだけでは何も起きない。
IEnumerableを実装したのを取り扱うことができる、foreachとかがあるから役に立つ。
しかし、RubyのEnumerableモジュールは違う。eachメソッドを定義して、取り込みを行う。
するとeachメソッドがあるのを前提に作られた、Enumerableモジュールのメソッドたちが読み込まれる。
結果、x.sortなどのような便利な取り扱いができる。


このモジュールというのがMix-inという機能を象徴している。
モジュールは、専ら取り込んで使われ、それ自体のインスタンスは存在しない、モジュールは継承をしない。
とまぁ、そんなもんです。
これは、多重継承で起きる菱形継承問題をうまく回避している…らしい。
菱形継承問題とは、こういう問題。
Aクラスに仮想メソッド(継承したクラスがオーバーライドできるメソッド)fooが定義されています。
これを継承したBクラス、Cクラスは共にfooメソッドをオーバーライドして内容を書き換えました。
DクラスはBクラス・Cクラスを共に継承しました。このときどのクラスで定義されたfooメソッドが実行されますか?
実際は優先順位を決めて行うことが多いけど、曖昧なのでJava・C#などでは禁止されています。Rubyも。
菱形継承問題については、互いに全く同じクラスを継承しないクラスたちを継承すればいいような気がする。


なるほど、それで継承することを禁止されたモジュールがあるわけですか。
これを見ていると、インターフェース内部にメソッドの内容を定義することに問題ないように見える。
まぁC#のインターフェースはインターフェースを継承するんだけどね。
うーん、これは結構な足かせだな。ここで菱形継承問題を起こしては何も意味がない。
インターフェースを継承しないインターフェースのみ、メソッドの内容を定義できる。
もしくは、インターフェースAを実装したインターフェースのみがインターフェースBを実装できると、
そういうことをBに定義すれば、Bを実装したクラスはAを実装していると知っているので、Aの機能をB内部のメソッドが活用できる。
非常に下品な制度だが、多分菱形継承ではない。
とまぁ、こうすればRubyのモジュールと大差ない。しかし、そんなものにインターフェースの名は与えんだろうね。
もっともこういうことを実現しようとして、C# 3.0の拡張メソッドは作られたわけだけどね。
けど拡張メソッドはわかりにくいしねぇ。


まぁなかなか難しい問題なのだが、多重継承にはもう1つ問題がある。
それはメソッド名が重複してしまうこと。これはRubyのモジュールと同じかな。
Perlでは継承するメソッドを指定しますけどね。それだけを継承すると。
C#でインターフェースの実装で実験してたが、これはこういう風に解決していた。

string Ifoo.method() {
return "Ifoo経由で呼び出した場合はこれ";
}

すなわち、obj.method()と、((Ifoo)obj).method()の結果は違うと言うこと。
前者は、objが基底クラスから継承したmethodメソッド、後者はそのクラスで定めたIfoo用のmethodメソッド。
なるほど、この程度だからこんな解決ができるが、Rubyのモジュールのような制度はこんな風には行かない。
その名前のメソッドがなければ、メソッドを取り込むといういい加減な解決はあまりよくない。
だって、そのクラスに急にその名前のメソッドが追加されるかも知れないから。すると予想とは違うことになる。
もしモジュールが実施されても、((Ifoo)obj).method()のような呼び出し方しかできないかもしれない。
そう考えると、C#がRubyのモジュールのようなものを導入せずに拡張メソッドという中途半端なもので納得できたのかわかる気がする。
拡張メソッドはあくまでも代用表現だからね。a.extmethod()は、extclass.extmethod(a)のように表現するのと一緒だし。