普通の構造化プログラマーがオブジェクト指向の存在意義を理解するコツ

オブジェクト指向言語の存在意義を理解するのは難しい?

id:amapetasさんによる、ちょっと興味深い記事がありました。
オブジェクト指向言語が流行した必然性について考える(1) - Programmer’s Log
そして、その記事の中で説明されているのですが、やはり、C言語など構造化言語のプログラマーにとってはオブジェクト指向の存在意義を理解するのがなかなか難しいところがあるようですね。

初心者向けの書籍を最近読んでいないので、最近の書籍ではうまく説明されているのかもしれませんが、そんな話を聞いたことがないので、たぶん今でもオブジェクト指向に関する説明の始まり方は

「世界は全部オブジェクトで出来ているんじゃぁぁーーー」

という「オブジェクト至高教への洗脳」から始まっているものと推察しますw テンション高めの説明から入るのでドン引きする人多数な感じがかなりアレですね。オブジェクト指向の説明は独特な説明から入るので宗教っぽいんですよね、若干。宗教という表現をさけるなら思想、哲学といえば柔らかいでしょうか。

僕がその手の初心者向け書籍を読んだ時に思った事は「なぜオブジェクト指向言語(Java)で書く必要があるのか? 構造化言語(C言語等)ではダメなのか? 何が違い、何がメリットなのか?」にうまく答えられていない、という疑問でした。オブジェクト指向の世界観の説明で手一杯でそこらへんをうまく説明できていない気がしました。

構造化言語(C言語等)ではできなくて、オブジェクト指向言語(JavaC++等)で出来るようになったものとは何か?

引用元の記事ではオブジェクト指向自然言語の構造と関連させて論じているのですが、ここでは論点を変えて普通の構造化言語のプログラマーオブジェクト指向のメリットを理解してもらうためにはどのように説明したらよいかという点について考えてみたいと思います。

伝統的なプログラマーの頭の中にある数のイメージ

我々は小さい頃から、まず、ものを数えるということから自然数として数の概念を習得します。そして、成長するにしたがって、金額やテストの点数など、他のところで使われる数も存在することを体験を通して徐々に学んでいきますが、日常生活では基本的には整数は数えたり、大小比較のために使うものという考え方が根強く存在するでしょう。
もちろん、このような普通の整数の概念は(範囲に注意すれば)プログラムを使って表現することができます。しかしながら、コンピューターの内部で表現される整数が特定の個数のビット(あるいはバイト列)からなるデータに過ぎないという発想は本来一般人にはない考え方であると思います。
実際、コンピューターの整数データは32ビットや64ビットなど表現可能な値の範囲という厄介な性質がある一方で、画像を構成する一個一個の画素(ピクセル)の明るさや色、音声データ、通信データなど様々なところで利用されています。ベテランのプログラマーの頭の中にある整数のイメージは、一般人のそれとは違っているのかもしれません。ビットやバイトなどを意識する必要のある(意識できる)比較的低水準な言語を利用することで、プログラマーはコンピューターの構造と近いレベルで考える必要がある反面、効率的なプログラムを記述できます。
ここで重要なのは、コンピューターの構造上の都合で決まっている32ビットや64ビットの情報を使って表現できる値を使う必要があるということであって、これは伝統的なプログラマーの頭では自然な単位なのかもしれませんが、一般人の頭ではまったく自然な単位ではないということです。しかし、コンピューターの処理能力の急激な進歩に従って、最近のアプリケーションはどんどん高度な機能を求められるようになってきています。たとえば、銀行のシステムの金額計算であれば、32ビットの範囲を超えたなどという理由で計算結果が不正になることなどはあってはいけません。

オブジェクトはデータを抽象化したもの

Javaなどのオブジェクト指向言語では、クラスを使ってデータ型を抽象化することで、文字列、誤差なく計算できる金額、日付、リストなどアプリケーションの記述に便利な値(=オブジェクト)を生成して利用できるようになります。実際、Javaでは文字列は基本型に準ずる形で簡単に扱うことができるようになっていますが、単純な文字列結合のような処理であっても、本来のVM上の動作から考えるとかなり複雑な処理が必要なのですが、そういった処理は抽象化されているので普通は考える必要がありません。
コンピューター内部の構造によらない抽象化されたデータ型を利用したり、独自にクラスとして定義したりできることは、このようなオブジェクト指向言語のメリットの一つと考えられます。コンピューター(VM)の作りの制約に縛られた基本型の値を使う代わりに、適切に抽象化されたオブジェクトを使うことで、ビットやバイトといった発想を忘れてよりアプリケーションの要求に近い塊の単位で簡単にロジックを組むことができるようになるのです。
そして、オブジェクトに対して呼び出し可能なメソッドは、intなどの基本データ型に対する+などの演算に近いものであると考えることができます。Javaでは残念ながら独自の演算子を定義することはできませんが、実際にC++などの多くの言語ではクラスに対して演算子を定義することができます。
さらに、基本型の演算に対しても一種のポリモーフィズムは存在しています。*1実際、Javaのint型とfloat型では同じ32ビットでもまったく異なる内部表現を使っているのですが、同じ+演算子を使って足し算を実行することができます。しかし、両者はオーバーフローの有無など、かなり異なる振る舞いをします。

オブジェクト指向の入門書が理解を妨げる?

本来はSmalltalkRubyのように「すべてがオブジェクト」という純粋なオブジェクト指向の世界で考えた方が分かりやすいのですが、普通の構造化言語のプログラマーが最初にオブジェクト指向を学習するには、「社長と社員との関連」「哺乳類も犬もすべてオブジェクト」などということを考えるよりも、intなどの基本型や構造体の値に対する自然な拡張として、段階的にオブジェクトを考える方がしっくりくるのではないでしょうか?私自身も最初にオブジェクト指向を学習した際にはそのようなプロセスで徐々に理解しました。
多くのオブジェクト指向の入門書は、伝統的なプログラミングの考え方とはかけ離れた世界でオブジェクト指向を語ろうとする傾向があるので、かえって構造化プログラミングの知識があると理解を妨げるところがあるかもしれません。つまり、これらの入門書では、ちょっと便利なデータ型を定義できるという段階をスキップして、いきなり実世界の「もの」の関係をモデル化するところから説明しようとするために、かえってプログラミングとの関連性が見えにくくなっているところはあると思います。
つまり、Objectを普通の英語の意味で実世界の「もの」と考えるのではなく、コンピューターのメモリ上に確保された値のことを指す専門用語としてとらえた方が、構造化言語のプログラマーにとってはしっくりくるのではないでしょうか。たまたま、顧客など実世界のエンティティに対応したオブジェクトも必要かもしれませんが、プログラムの都合上で必要な値の塊も立派なオブジェクトになり得ます。

プログラミングでオブジェクト指向を習得するステップ

ところで、C++、Objective C、Object PascalJavaといった言語では、比較的低水準な伝統的なプログラマー脳が必要な基本型と演算子を使ってコーディングを行うことも、クラスライブラリーを利用して高水準のオブジェクト指向プログラミングを行うことも可能です。複数のパラダイムが混在しているため、なかなかい理解しにくいというところもあるかもしれません。
まずは、配列、文字列、日付といった抽象データ型がオブジェクトの一種なのであるというところから慣れ、次に、

あたりを順番に理解していくようにすれば、理解しやすいのではないかと思います。そして、プログラミングで正しく独自のクラスの作成ができるようになってくれば、自然に業務ドメインなど実世界の問題も、クラスを使ってモデリングする力がついてくるはずです。

*1:Javaを含めて、ここで説明する数値演算に対するポリモーフィズムコンパイル時に決定されるので実際にはオーバーロードされたメソッドの呼び分けに近いものですが。

*2:簡単なスタックやリストなどを自作してみるのも学習のためにはよいですね。