オブジェクト指向はクソか?

はじめに

これは以前私がqiitaに投稿した記事です。

オブジェクト指向はクソか?

私は長らくJavaを用いて開発を行なってきましたが、最近、関数型言語であるClojureにより魅力を感じています。 そして関数型言語であるClojureについてなぜ惹かれるのかをいろいろと考えを巡らせているときにこの記事を偶然に見つけました。

記事は「Why OO Sucks」という刺激的なタイトルですが、自ら理解したいという目的もあり、翻訳しました。

http://www.sics.se/~joe/bluetail/vol1/v1_oo.html

実は、この記事は関数型言語のひとつであるErlangの作者であるJoe Armstrongが書いたのです。そして翻訳したあとから知ったのですが、書かれてから少し時間が経っているため、何人かがすでに訳されているようです。そして数多いディスカッションがなされているようです。

誤訳やわかりづらいところがあるかと思いますが、お許し下さい。

Joe Armstrongのオブジェクト指向はクソだ!

オブジェクト指向について

実は私は最初にオブジェクト指向を知った時、オブジェクト指向に対して批判的でした。でも、直感的に誤っていると思っただけで「なぜか?」はわかりませんでした。

そして、オブジェクト指向がとても有名になってしまってからは、OOPを批判することは教会で罵ること("swearing in church")のように思われました。

かくしてオブジェクト指向であることはすべての尊敬されるべき言語が持つべき特質のようになってしまったのです。

私が開発したErlangが有名になってからは、Erlangオブジェクト指向言語であるかどうかよく聞かれました。もちろん正しい答えは、「まったく違います!」です。しかし、この答えを大きな声ではあえて言わなかったのです。

そして、ついに我々はこの質問に対する素晴らしい回答を発明をしたのです。それは普通のひとにはErlangがOOの一種であるような印象を与えるように、しかしながら注意深く私の説明を聞いている人々には実はそうではないことが分かるような答えを思いついたのでした。

私はあるフランスで開催された第7回のIEEEのロジックプログラミングカンファレンスでのフランスIBMの社長のKeyノートスピーチを思い出しました。IBM Prologは多くのOOの拡張を追加したことについて質問されたのですが、それは顧客が要求したからであると答えたのでした。

私はその回答が何の良心の呵責や自己反省がない、すなわち「これが正しい道なのか」ということを考えてないなんて単純な対応だろうかと疑いを持ちました。

オブジェクト指向が"Suck"である理由

私のOOPに対する反対意見はOOの基本的なアイデアに対するものも含まれます。以下にそのアイデアのアウトラインと私の反対意見を述べます。

反論その1 - データ構造と機能は一緒にすべきではない

(Objection 1 - Data structure and functions should not be bound together)

オブジェクトは関数とデータ構造が分割出来ない単位としてひとつまとめにしています。しかし、私はこれこそが基本的でかつ大きな誤りであると考えています。なぜなら、関数とデータは異なる世界に存在するからです。なぜでしょう。関数は何かを実行します。そして関数はインプットとアウトプットを持ちます。関数の入力と出力はデータ構造であり、関数により変更されます。

多くの言語の関数は命令のシーケンスから作られます。すなわち、「まずはこれを実行して、次はこれを実行しなさい」という手順です。関数を理解するためにはどのような順序でものごとが実行されるかを理解しなければなりません(遅延評価をサポートする関数型言語と論理型言語ではこの制限は緩やかです)。

データ構造はそれそのものです。これらは何もしません。これらは本来宣言的なものなのです。データ構造を理解することは関数を理解することよりもはるかに簡単なことなのです。

関数は入力から出力へと変換するためのブラックボックスです。入力と出力を理解すれば関数を理解したことになります。でも理解したからと言って関数を記述できることにはなりません。

関数は通常、コンピュータシステムにおいてジョブがデータ構造をT1からT2に変換することの観察を通して理解したことになります。

このように関数とデータ構造は全く異なるタイプの生き物です。そしてそれを同じカゴの中に閉じ込めるのは全く持って間違っていることなのです。

反論その2 - すべてはオブジェクトではない

(Objection 2 - Everything has to be an object.)

「時刻」について考えてみましょう。OO言語の立場での「時刻」はオブジェクトであるべきです。でも、非OO言語では「時刻」はデータタイプのインスタンスです。例えばErlangでは「時刻」の多くのバラエティがあります。これらはとても明白で曖昧さがありません。

-deftype day() = 1..31.
-deftype month() = 1..12.
-deftype year() = int().
-deftype hour() = 1..24.
-deftype minute() = 1..60.
-deftype second() = 1..60.
-deftype abstime() = {abstime, year(), month(), day(), hour(), min(), sec()}.
-deftype hms() = {hms, hour(), min(), sec()}.
...

これらの定義はどの特定のオブジェクトにも属していません。これらはどこでも利用できるデータ構造で「時刻」を表現しており、システムのどの関数からでも利用することができます。

そしてどのようなメソッドにも関連していません。

反論その3-オブジェクト指向言語ではデータタイプ定義はあちこちに散らばってしまう

(Objection 3 - In an OOPL data type definitions are spread out all over the place.)

オブジェクト指向ではデータタイプはオブジェクトとして定義されます。そうするとデータタイプは一箇所で見つけることができません。ErlangやCではすべての私のデータは一箇所であるinclude fileもしくはデータ辞書でみつけることができます。でも、OOPLではこのようなことができず、データタイプ定義はあちこちに散らばってしまいます。

この例を示しましょう。私が汎用的なデータ構造を定義したいとします。この汎用データタイプとはシステムのすべての場所で使えるものです。

LISPプログラマであれば「わずかな汎用データタイプと多くの小さな関数がこれらに作用すること」が「数多いデータタイプとこれらに作用する少ない数の関数よりも良いこと」という真実を知っています。

そして、汎用データ構造としてリンクリストや配列、ハッシュテーブルがあり、さらには時刻、日付、ファイル名などがあります。

OOPLでは私は汎用的なデータ構造を定義する際にはなにかベースオブジェクトの中から選択しなければならないというとても面倒くさいことをしなければなりません。そして、そのデータ構造はこのオブジェクトを継承して作る必要があります。もし何か「時刻」のオブジェクトを定義したい場合、これがどのベースオブジェクトに所属していて、それ自体、どのようなオブジェクトであるか考えなければならないのです。

反論その4 - オブジェクトはプライベートな状態を持っている

(Objection 4 - Objects have private state.)

状態(state)は諸悪の根源です。特に関数の副作用は避けるべきです。しかしながらプログラミング言語において状態は好ましいものではないのに関わらず、実世界では状態は至るところに存在します。

例えば私は銀行口座の状態、すなわちに預金残高に大いなる関心があります。そしていつ私が入金や出金をする場合には銀行の口座が正しく更新されなければとても困ったことになります。

実世界でこのような状態が存在したとして、この状態を取り扱うためにはプログラミング言語はどのような仕組みを提供すればよいのでしょうか。

OOPLはプログラマから状態を隠しなさいといいます。状態は隠されてアクセス関数を通してしか見えません。

伝統的なプログラミング言語であるCやPasalでは状態変数の可視性は言語のスコープのルールによってコントロールされます。

でも、純粋に宣言的な言語では状態は存在しないことになっています。このような宣言的言語ではシステムのグローバルな状態はすべての関数の入力や出力になりうるのです。関数型言語におけるモナドや論理型言語におけるDCGでは「状態はあたかも関係のないように」プログラミングすることができます。にも関わらず必要な場合にはこれらのシステムの状態に完全にアクセスをすることができるのです。

ほんとうは「プログラマから状態を隠す」というOOPLで選択されたオプションはとても悪いものなのです。状態を公開して状態の厄介さを最小限にしようとする努力をすべきなのに、その代わりとしてOOPLではそれを隠し去ってしまったのです。

オブジェクトが広まった理由

オブジェクト指向が広まった理由は次のとおりだといわれています。

Reason 1 - It was thought to be easy to learn. (簡単に学べると思われていたから) Reason 2 - It was thought to make code reuse easier. (再利用がより簡単だと思われているから) Reason 3 - It was hyped. (売り込まれたから) Reason 4 - It created a new software industry. (新しいソフトウエア産業を作ったから)

しかし、1と2が事実であるという証拠はまったくを持って見たことがありません。それでも実際にオブジェクト指向が広まった理由はテクノロジーに対する逆向きの作用であると思われます。つまり、あるテクノロジーがひどすぎると、そのテクノロジー自体が作った問題を解決するための新たなビジネスが登場して、金儲けをしたい人たちのアイデアになるのです。実はこのことが実際のOOPに対する推進力になっているということなのです。