2020/5/13追記
**オブジェクト指向と哲学の関係について書いた記事ではないです。**せっかくだしQiitaっぽいタイトルつけようと思ったら結果的に釣りっぽくなってしまった
概要
オブジェクト指向とは何か?ということを真面目に調べていくと、オブジェクト指向には二種類ある、という話に突き当たる。sumim氏のQuora回答などを参照。
- Smalltalkの設計者アラン・ケイによる、メッセージング重視のオブジェクト指向
- C++の設計者ストラウストラップによる、クラス重視のオブジェクト指向
今回はこの前者のオブジェクト指向について、アラン・ケイの書きものを読んで調べた結果をまとめ、コメントを付す。
参考文献は最後にまとめて出す。参照元は「(AOO)」のように略記で示す。
アラン・ケイのオブジェクト指向
OOPは私にとって、メッセージング、状態処理の局所的な保持・保護と隠蔽、そしてあらゆる事象の徹底的遅延束縛のみを意味する。(AOO)
この引用でアラン・ケイは、オブジェクト指向の中心要素として、メッセージング、状態処理の隠蔽、徹底的遅延束縛の3つを挙げている。これに加えアラン・ケイが重要視することとして、オブジェクトを「アイデアidea」の観点から捉える設計がある。この4つを以下で説明しよう。
4要素のうち、状態処理の隠蔽・遅延束縛は、メッセージング・アイデア視点の設計に対してモチベーションを与えるものと考えるとわかりやすい(それに尽きるものではないが)。
メッセージング
まずとことん大雑把に述べる。メッセージングの考え方とは、システムを記述する基礎的な概念に、オブジェクトへメッセージを送る、という3つを採用することをいう。
もう一段具体的にいうと、メッセージングとは、プログラムを次のような統語論・意味論上の原則に基づいて記述することをいう。
統語論上の原則として、プログラムの基礎単位に、次のようなメッセージ送信表現を採用する。
[オブジェクト] [送られるメッセージ]
意味論上の原則として、メッセージ送信表現が何を意味するかは、メッセージを受けるオブジェクトによって決められる(SEO)。
この考え方の重要なところは次の二点だ。
- メッセージはそれ自体でいかなる意味も持たない
- メッセージが何を意味するか(システムとして何を起こすか)はオブジェクトが解釈する
例えば普通sqrt(3)
と書いたとき、sqrt
はある特定のアルゴリズムによるルートの計算処理を意味し、3
はある特定の数値データを意味している。これと異なり、メッセージはそれ自体では何も意味しない。
メッセージが意味を獲得するのは、それが特定のオブジェクトに送付され、オブジェクトによって解釈されたときである。オブジェクトは自らの解釈に基づいて、メッセージに従い何らかの計算処理を走らせる。
言い換えると、メッセージとはコードであり、オブジェクトはそのインタプリタであるとも言える(EHSにそれに近い記述もある)。だからメッセージングに従ったシステムの記述とは、システムを複数のインタプリタと、それに対するコードの送信としてみる捉え方とも言える。
オブジェクトをアイデアから捉える
それぞれのオブジェクトは一つのアイデアideaと考えることができる。アイデアは有用かもしれない振る舞いを保持しており、振る舞いのリクエストを受けることができる(命令はできない)。(GAS)
メッセージングの概念を使ってシステムを設計する上では、オブジェクトを単なるデータではなく、アイデアideaとして捉えるべきである。アラン・ケイ自身は(私が読んだ範囲では)あまり使わない言葉だが、オブジェクトを責務の観点で捉えよ、と言い換えても良い。
アラン・ケイによると、例えメッセージングの枠組みでシステムを設計していたとしても、いわゆるゲッター/セッターをメッセージとして多用した設計は、オブジェクト指向の力を引き出しているとは言えない。
もしあなたがセッターを使っているなら、あなたは本当はオブジェクトを扱っているわけではなく、それっぽいデータ構造を使っているだけだ。オブジェクトをこのように「抽象データ型」として扱うのは、オブジェクト指向プログラミング・設計の精神に背いている。(GAS)
正しい設計方針は、オブジェクトをアイデアとして捉えることだ。例えば実際にソートを実行するアルゴリズムはたくさんあっても、それらはただ一つのソートのアイデアを実行する手段である。このように抽象化された「やるべきこと」=責務の概念を表現するものとして、オブジェクトを捉えるべきである。
徹底的遅延束縛
遅延束縛とは、表現の意味の決定=束縛を、できる限り後回しにすることを指す。「徹底的」というからには、できる限り遅く、できる限り自由に、表現の意味を決めなければらない。
メッセージングを基礎単位として取ることは、より徹底的な遅延束縛を可能にする。というのも、メッセージそれ自体は意味を持たず、実際にメッセージがオブジェクトに送信されてはじめて、意味が決まるからである。いわゆるランタイムディスパッチ、ポリモルフィズムのことだ。同じメッセージであっても、実行時にどのオブジェクトに送信されるかによって、結びつく処理を変えることができる。
オブジェクトをデータではなくアイデアの観点から捉えた設計も、徹底的遅延束縛を後押しする。例えばソートアルゴリズムによって一時的メモリの使い方は異なる。同じアイデアの実現方法であっても、どんなデータをどう利用するかはそれぞれ異なる。データではなくアイデアという観点からシステムを抽象化すれば、どんなデータを使うのか、あるいはデータを全く使わないのか、そういったこともすべて遅延束縛されるべき実装の詳細として自由自在に後決めできる。
これに加えてSmalltalkでは、実行中にコーディングしてメッセージの解釈を書き換えるという離れ業ができる。例えばオブジェクトが解釈できないメッセージを受け取ってエラーを起こしたとき、ユーザーがメッセージの解釈をその場で追加する(メソッドを追加する)ことができる。この点において、Smalltalkはより徹底的な遅延束縛をサポートしている。
なおなぜアラン・ケイが遅延束縛を重要視するかと言うと、どうやらアジャイル開発的な発想があるようだ。いきなり正解を作ろうとするのを諦める。とりあえず動くものを作った上で、その動くものを、動かしながらましに直していく。そのような開発が可能になるためには、抽象的な記述は固定した上で、結びつく具体的な処理を変えていくこと、つまり遅延束縛が重要になるわけだ(SEO)。
状態処理の隠蔽
状態変化、変数が指す値の変化は、プログラムの内容を不明瞭にし、トラブルの温床となる。なぜなら変化した状態を参照する関数は、変化の前後で異なる処理を起こすからだ(これを指してアラン・ケイは、変数への値の割り当てはメタレベルの変化である、と言っている(AOM))。そのため、状態変化に何らかの制限をかけたくなる。
メッセージングを基礎単位として取ることは、この制限を可能にする。メッセージングを使ってプログラムが書かれている場合、状態変化はメッセージをオブジェクトが解釈し、自らが支配するメモリを書き換えてはじめて起こる。そのため、直接の状態変化はオブジェクトの内部でしか起こせないことになる。外部からは、オブジェクトにメッセージを送り、そのオブジェクトが状態変化として解釈してくれて、はじめて間接的に状態変化が起こせる。いわゆるカプセル化で、状態変化を局所化できるわけだ。
また、ゲッター/セッターを使った設計は、状態処理の隠蔽を重視する観点からはあまり望ましくない。ゲッター/セッターを使用すれば、状態そのものが外部の関心事となるとともに、外部からかなり自由に状態を弄ることができるからである。逆にオブジェクトをアイデアとして捉えたとき、状態変化はアイデアを実現するための二次的な詳細として、オブジェクトの内部に隠蔽される。外部からも直接の関心事ではなくなり、理想的には状態変化を考慮せず設計できる。
コメント
ストラウストラップのオブジェクト指向との違い
ストラウストラップのオブジェクト指向については別記事にまとめた。簡単に言うと、抽象データ型(クラス)と継承を使うプログラミングが彼にとってのオブジェクト指向である。
アラン・ケイのオブジェクト指向にとっては、クラスと継承は本質的なものではない。もちろん、クラスのインスタンスに対するメソッド呼び出しをメッセージングとみなし、継承に基づくポリモルフィズムによって遅延束縛を行えば、アラン・ケイのオブジェクト指向を部分的に実現することはできる。だが、それが唯一の実現方法というわけではない(もともとSmalltalkに継承の機能はなかった)。
逆にストラウストラップのオブジェクト指向にとっては、メッセージング・オブジェクトをアイデアとして捉える・徹底的遅延束縛・状態処理の隠蔽といったアイデアは本質的なものではない(継承に基づくポリモルフィズムという意味での遅延束縛は重要視していたようだが)。なんなら、型を重視するストラウストラップの考えは、動いているシステムに対してガンガン後付けで処理を入れ替える徹底的遅延束縛の思想と緊張関係にあるとも言える。
関数型プログラミングとの関係
関数型プログラミングとオブジェクト指向は両立するか?という話題がある。アラン・ケイのオブジェクト指向と関数型プログラミングは、同じ問題を解く別のやり方と捉えることができるだろう。
関数型プログラミング(のある解釈)は、状態変化を問題視して、その一切をプログラムから排除する。一方アラン・ケイのオブジェクト指向は、状態変化を問題視して、それをオブジェクトの内部に隠蔽する。そのため、両立するかどうかはともかく、関数型プログラミングを採用した場合、アラン・ケイのオブジェクト指向を追加で採用する必要は(状態変化への対処という意味では)なくなる。
参考文献
- (EHS)The Early History of Smalltalk
- (AOO)Dr. Alan Kay on the Meaning of “Object-Oriented Programming”
- (AOM)Alan Kay On Messaging
- (SEO)Is “Software Engineering” an Oxymoron?
- (GAS)In object-oriented programming, why is it bad practice to make data members public when the get() & set() public members modify it anyway?