Java Generics Hell - オブジェクト指向
Java Generics Hell アドベントカレンダー 2日目。
読者の推奨スキルとしてはOCJP Silverぐらいを想定している。
前回は与太話だった。ジェネリクスの話をする前にOOP(オブジェクト指向プログラミング)について整理しておかねばならない。
オブジェクト指向とは
オブジェクト指向が何かという点についてはなかなか難しい。
Smalltalkを作ったアラン・ケイが「オブジェクト指向」という言葉を初めて用いたといわれるが、この「オブジェクト指向」はJava言語の教育の過程で一般に教えられる「オブジェクト指向」とはかなりイメージが違う。
アラン・ケイが「オブジェクト指向」という言葉を創った当初は、Smalltalk システムが体現した「パーソナルコンピューティングに関わる全てを『オブジェクト』とそれらの間で交わされる『メッセージ送信』によって表現すること」を意味していた。しかしのちに、C++ の設計者として知られるビャーネ・ストロヴストルップが(自身、Smalltalk の影響は受けていないと主張する)C++ の設計を通じて整理し発表した「『継承』機構と『多態性』を付加した『抽象データ型』のスーパーセット」という考え方として広く認知されるようになった(カプセル化、継承、多態性)。現在は、両者の渾然一体化した曖昧な概念として語られることが多い。
Smalltalk とオブジェクト指向
要するに、「オブジェクト指向」と呼ばれる概念はアラン・ケイ系統とビャーネ系統とがあるわけだ。アランのオブジェクト指向は「メッセージング」というアイデアが中核になっている。よって、本稿ではそれらは「メッセージング」と呼ぶこととし、概念を呼び分けよう。Java言語でのオブジェクト指向はビャーネのC++の影響を強く受けている。本稿では特に断りがなければ「オブジェクト指向」はこのC++系統のオブジェクト指向としよう。
オブジェクト指向の三大要素?
しばしば「オブジェクト指向の三大要素」と銘打って「継承、カプセル化、ポリモーフィズム」が語られることがある。ものによっては「クラス、カプセル化、ポリモーフィズム」となっている記述も見かける。なお、原典はなんだかよくわからない。
この論に基づくと継承がないものはオブジェクト指向にあらず、といった思想にも陥りそうだが、クラスの継承を持たないプログラミング言語でも「オブジェクト指向」とされる。いわゆる動的言語など呼ばれるものなどでも「オブジェクト指向」だ。
「オブジェクト指向」の中心概念はなんなのか?という問いはまた難しく、多くの派閥があることだろう。以下は筆者の私見であるとまず断っておく。
「継承」という概念は「ポリモーフィズム」はおそらく不可分な概念であろうと思う。クラスを継承したとして、ポリモーフィズムがなかったとしたら、それは「継承」なのであろうか。クラスの継承がないプログラミング言語もある。「継承」はおそらくオブジェクト指向という概念に必須ではない。Javaのような静的言語(つまりコンパイルによって静的に型の整合性をチェックできる言語)では「継承」といった部分については「型システム」という概念で分離したほうが話がすっきりすると思うのである。
もちろん、「ジェネリクス」はその「型システム」の一要素ということになる。
カプセル化については設計指針として外部から内部を隠蔽し、窓口を限定し明確化することで柔軟性、保守性を高めることができる、が、これは「オブジェクト指向」そのものの構成要因ではない。つまり、オブジェクト指向を活かすにはうまくカプセル化をしなさいよ、という指針であって、オブジェクト指向プログラミング言語を採用すれば直ちにカプセル化されるものでもない。そういう意味では、この三大要素とやらに並べられる要素はどうもそろっていない。こじ付け的に3つレベル感のあわない要素を挙げたようなものに思える。
対してポリモーフィズムは「オブジェクト指向」そのものの構成要素である、と私は考える。つまり、データ(Javaでいえばフィールド)と操作(Javaでいえばメソッド)をひとまとめにし、オブジェクトごとに操作は挙動が変わりうる、ということだ。これはJavaももちろんのこと、JavaScriptのようないわゆる動的言語であっても同じことだ。ただ、Javaではオブジェクトの操作を異なるものにするには継承を用いるが、JavaScriptであればオブジェクトのfunctionを異なるもので上書きすればよい。
つまり、オブジェクトにより挙動が異なるわけで、これこそが「オブジェクト指向」の中核であるように思えるし、このシンプルなアイデアがもたらす恩恵が大きいからこそ、現代のプログラミング言語ではこれほどまでにオブジェクト指向が重視されるのであろう。
ところで三大要素が「継承、カプセル化、ポリモーフィズム」、ものによっては「クラス、カプセル化、ポリモーフィズム」であると言った。ここで後者の「クラス」はどうか。先ほど「データと操作をひとまとめに」と言ったが、これこそ「クラス」と呼ばれるものである。そして、これは挙動としてはポリモーフィズムすることが前提である。となると、「クラス」と「ポリモーフィズム」というのはわりと重複するもので「クラス」において「ポリモーフィズム」はやはり不可分である。これもまた3つ挙げるためにこじつけた感じがする。いわゆる動的言語などであれば「継承」を挙げるのが不適切となるので代わりに「クラス」とした、といったところなのではないか。
まとめ
- 「オブジェクト指向」という言葉にはアラン・ケイ系統(Smalltalk)とビャーネ系統(C++)があり用語の混乱がみられる
- オブジェクト指向の三大要素といわれる概念は胡散臭い
- 筆者の私見となるが「ポリモーフィズム」こそが中核ではないか
- 継承によってポリモーフィズムさせる言語(Javaはここ)もあれば、よりダイナミックにメソッドを上書きできる言語もある。それもまたポリモーフィズムである
- カプセル化はオブジェクト指向をより活かすための設計指針のようなもの
- 継承は型システムの段でとりあげる
さて、次回は型システムについて取り上げたい。まずはJavaの型システムの基礎となるリスコフの置換原則である。