継承という手段

ポリモーフィズムは継承の面白い副作用..なんかじゃない - みねこあ のコメント欄より。田辺さんとのやり取りで、私が相当おかしなことを言っている件について。



インターフェイス継承」という言葉が、仕様を引き継ぐことなのか、Java の Interface のような 実装をまったく含まないクラスからの継承を指すのかが曖昧に感じられるため、前のエントリではお茶を濁していたのですが、これは本質ではなく、さらなる混沌とモヤモヤ時空を作り出してしまっています。また脳内知識だけで書いてしまったための「嘘」も見受けられます。その結果、新たな オレオレOOP を作り出さんとばかりな、感じになっていて、これは非常によくないです。だめだめだ、あたし。


なので、ちゃんと「インターフェイス継承」と「実装継承」で説明しようと思いました。まず「インターフェイス継承」の、誤解を呼ばない別のいい表現がないかな、と捜してみたら 型継承(type inheritance) と言う言い方もあることを発見。よし、これでいきます!



というわけで、このエントリは、ポリモーフィズムは継承の面白い副作用..なんかじゃない - みねこあ の再チャレンジです。


* * *


まずは用語整理。

型継承(type inheritance)

型と型をどのように関連付けるかです。is-a によるモデリングに使われるもので、重要な性質としては 包摂(subsumption)があります。

包摂とは、型Foobar が 型Foo のサブタイプであるなら、Foobar オブジェクトは Foobar型の参照だけでなく、Foo型の参照にも代入できるということです。

実装継承(implementation inheritance)

どのようにクラスを組織化して、コードを再利用するか、というものです。非 is-a。has-a か?

実装継承だけを行える機能は Java には無いですが、C++ の private継承 / protected継承 は実装継承だけを行います。public継承すると、型継承と実装継承の両方を行います。

Eiffel は フィーチャごとに 実装継承するか、型継承をするかを指定できます。


* * *


ポリモーフィズムは、型継承 や ダックタイピング(duck typing)、総称(genericity) で実現します。一方、差分プログラミングは、実装継承や集約(委譲)で実現します。

あるクラスを(C++のpublic継承相当で) 継承するとき、もしメソッドをオーバーライドしてしまうなら、そのメソッドについては 型継承しかされていません。このとき目的とされるのはポリモーフィズムです。

メソッドをオーバーライドしないなら、実装継承と型継承の両方が行われています。このとき目的とされるのは差分プログラミングですが、型継承部分は どちらかというかオマケというか、「オートで仕様もマージしてくれるのって便利だよね」という便利機能です*1


* * *


実際のところ、OOP において継承は手段にしか過ぎません。ポリモーフィズムをしたいか、差分プログラミングをしたいかです。しかし、Java のような静的型付け言語では、ポリモーフィズムの実現手段として 継承 しか存在しませんでした(過去形。今は総称がある)。なので、型継承とポリモーフィズムは不可分になっています。

また、Java では 型継承を伴わない実装継承を実現する方法がありません。そのため実装継承と型継承が不可分である問題もあります*2

結果、ポリモーフィズムと差分プログラミングを混同しやすいように、言語が誘導してしまっていて、この混乱が「OOPの難しさ」として認知されているように感じます。

混乱しやすいもの(=難しいもの)についてそれをサポートするのがノウハウやその教育で、使い方のメッサ難しい C++ のこの手のドキュメントの多さ分厚さはだからピカイチ(w)。これは知恵と勇気(とC++の場合はテンプレートメタプログラミングで)で克服できるものです。同様に Java風な いまどきのOOPL界隈で 仕様と実装の分離が声高に叫ばれるのは、そこが混乱しやすい元凶であるから...と見るのは、少々穿った見方でしょうか?


* * *


動的型付けOOPL では、型継承 によるポリモーフィズムはありません*3。だから継承 = 実装継承 になります。「ポリモーフィズム」と「差分プログラミング」という別のものを実現する手段もまた別のものになっているため、これらが別のものだと認知しやすくなっています。

動的型付けOOPLをOOPの教育に使う効果は、「ポリモーフィズム」と「差分プログラミング」が 手段も含めて別のものなので、別々に(= 片方だけでも)教えられるということと、一度別のものとして認知できれば、Java風静的型付け言語の世界に戻ったときにも、手段に惑わされずに別のものとして考えられるようになることです。デメリットは不可分になってしまっているものをうまく折り合いをつけるノウハウが0のままであることです。

職場教育として考える場合、結局どちらが早く多くの人を 一定のレベルまで引き上げられるかですので、仕事言語が Java風静的型付け言語である場合、一概に 動的型付けOOPL が良いとは言い切れません。



...さて、今度はどうでしょ。またダメダメだったらどうしよう orz

参考文献

オブジェクト指向言語のはなし あなたはなにを選ぶのか―Java、Eiffel、C++?

オブジェクト指向言語のはなし あなたはなにを選ぶのか―Java、Eiffel、C++?

  • 作者: イアンジョイナー,Ian Joyner,白根健司
  • 出版社/メーカー: ピアソンエデュケーション
  • 発売日: 2000/05
  • メディア: 単行本
  • 購入: 1人 クリック: 23回
  • この商品を含むブログ (8件) を見る

参考、というかパクリ元です。

オススメの本ですが、「Eiffel 最高! それに比べて C++Java は...」という本なので、言語愛によっては非常にムカつく本であります。(あたしゃこのタイトルで Smalltalk がサクっと無視されたことに腹が立ちましたがw)

余談

ちなみに、↑の本によると、Meyer の オブジェクト指向入門 第2版 の 24章にも継承の種類による記述があって、そこでは継承は 12種類に分類し、大きく 3つにカテゴライズしているそうなのですが、日本語訳版はまだ18章までしか出ていません。

・・・まさか下巻で待たされることになるとはおもってませんでしたよ。あたしゃあの厚さの英語の本を読み切る自信がないので、長らく日本語版を待ちながら見送ってましたが、これで下巻がでないなら、覚悟して一生懸命原書を読むしかないかもしれない。

*1:コレを勝手にやってくれないと、void sub::fooFunc(){ base::fooFunc(); } みたいなのを書くハメになりますし、積極的に名前を変えたい機会はあまりないし

*2:しかし C++ の 「private 継承 があること」は、それよりも多くの混乱の源となっていて、Java等にそれが無いのは その改善の結果であり、問題は少々あるけれど断然良いトレードオフだと思います。この少々の問題をフォローするための心配りもしっかりありますしね

*3:ホントか?