クラスはサブルーチン由来(Simula)の補足

某しっくりこないな エントリですが、コメント欄でガンガンご本人が燃料を投下するというすさまじい事態になっています。炎上の鎮火方法に「燃やしつくす」ことを選ぶとは、なんとも恐ろしいことをする御仁です(これが生き残りの極意か....)。

と、まぁ、人の心配は置いておいて、今は自分のこと。

元ネタの炎上と相まって、わたしのとこのエントリもつられてブクマが予想外に増えていく。あのエントリは勢いと記憶だけで書いてしまっていて、あんまり注目されるとちょっとヤバいというか、具体的には 書く前にちゃんと原典にあたってなかったりですとか、ちょっとアレレ?な事を書いてたりですとか、残したツッコミどころが案外多くって、類焼しないかと恐怖を感じた一週間でした。

というわけで、補足説明。

補足の1

先のエントリーでは「サブルーチン」と言ってしまってますが、正確には Simula (SIMULA 67) の クラスは、ALGOL 60 のブロック を拡張したものです。これは C のブロック {...} と同じです。

「Cでは実はブロック毎に局所変数をもてますよ」というマニアックな事を知っている方には「C のブロックと同じだよ」でしっくりきますが、この話題の文脈ではマニアックでない、名前付きでレキシカルな位置に縛り付けられてない、再利用可能なブロックであるサブルーチンのほうがイメージしやすいかと。

ダール先生とホーア先生の「階層的プログラミング構造」より引用すると、ALGOL 60 のブロックに対し、

プログラムテキストの一部分であるブロックと,計算過程(の1つの構成要素)である動的なブロックの実例が明確に区別されている

と、気がつきにくいけれど ブロックにだって実例(instance)があるんだよ、と強調したうえで、

新しいブロックの実例を作り出すプログラムでは,制御が戻ってきたときにには,その実例は消滅しているので,“もの”を持って存在している対象として,それと相互に作用し合うことは決してできないという欠点がある.(中略)つまり,ブロックの演算的な側面が強調されすぎているのである.

SIMULA 67 では, ブロックの実例はそれを呼ぶ出す文より長い間存在することが出来るし,プログラムでそれを参照する必要のある限り存在し続けることが出来る.

と言う風に、ブロックのデータ的側面にも着目して ALGOL 60 のブロックを拡張した結果 半コルーチンとなったこと。それを

呼び出されたときだけでなく,存在し続けるブロックの実例の元になる手続きをクラス(Class)という.そして,その対象(object) をいう.

クラスとオブジェクトと名づけたことが書いてあります。

構造化プログラミング (サイエンスライブラリ情報電算機 32)

構造化プログラミング (サイエンスライブラリ情報電算機 32)

補足の2

たとえ Simula でどのようにクラスが作られたからといって、だから「このような使い方が正しい」とは言えないというか。言えるのは「こんな性質があるよ(こんなことが出きるよ)」止まり。そこから先は別の話です・・そこはもう少し強調しておくべきだったかも。


C++ は Simulaの 発明した クラスとオブジェクトをつかって、「あ、これを使えば抽象データ型(ADT)を表現できちゃうじゃん」な ことをした言語です。(ここでの ADTは、要するに出来合いのデータ型とまったく同じ使い勝手のデータ型をユーザーが作れる機能・・くらいの意味合いで)

ストラウストラップ先生の「プログラミング言語 C++」では、オブジェクト指向プログラミングを、ADTに実装継承による差分プログラミングを組み合わせたもの(と同時に概念の階層構造を持たせたもの)のようにかかれています。なのでクラスのデータ的側面を強調しすぎるきらいは、むしろ C++ らしいところかも。

プログラミング言語C++ (アスキーアジソンウェスレイシリーズ―Ascii Addison Wesley programming series)

プログラミング言語C++ (アスキーアジソンウェスレイシリーズ―Ascii Addison Wesley programming series)

が! そんなのは (昔 && C++) な OOP のお話で、今時C++界隈だって、「それが OOP だ」とは言わないよね。

デザインパターンが普通に知れ渡っていて、C++ in depth シリーズ等が既に常識になっている 今時の C++開発では、OOPは メイヤー先生の 「オブジェクト指向入門」の OOP と同じと言ってよいと思います。

すくなくても昔の 毛の生えたADTと手続きで組まれるプログラム──「デザインパターン」の序文

一度デザインパターンを理解し、「ん?」ではなく「あっ、そうか!」という経験をすれば、今までと同じ方法オブジェクト指向設計をしようとは思わなくなるだろう。そして設計プロダクトの柔軟性、モジュール性、再利用性、および理解のしやすさをより高めるためにはどうすればよいかがわかるだろう。そしてまさしくこれらのことこそ、読者の皆さんがそもそもオブジェクト指向技術に興味を持った理由ではないだろうか。

(強調はわたし)

で「今までの方法」と言われてしまっている手法を「それはOOPじゃない!」と言ってしまうのは、この手の文脈ではアリだとわたしは思います。

オブジェクト指向における再利用のためのデザインパターン

オブジェクト指向における再利用のためのデザインパターン

補足の3

補足と言うかおまけです。

メイヤー先生の OOP は、「オブジェクト指向入門第二版 原則・コンセプト」から引用すると、

オブジェクト指向ではない手法では、モジュールの概念と型の概念は別のものである。クラスという概念においてもっとも顕著な属性は、クラスがこれら2つの概念を包括し、1つの言語的構造に併合した事である。クラスはモジュールであり、ソフトウェア分解の単位である。しかし、同時に型でもある

になります。「モジュールであり同時に型である、クラス」は金言です。

ここで一つ注意ですが、メイヤー先生の言う「モジュール」とは、プログラムの構造化部品のことで、例えば、サブルーチンもモジュールの一種になります。Cのモジュール(翻訳単位を一塊と見なすやつ)とは違います。

特に肝は、データだけでなく、モジュールも型であること。これにより、分割統治した部品(モジュール)の部品間の関係の正しさを静的にチェックできます。

具体的には...普通の手続き言語ではデータに対して 正しく受け渡しが行われているか静的に型チェックすることが出来ますが、OOP では加えてモジュールの接合──つまりサブルーチンみたいなものに対しても、呼び出し元と呼び出し先が正しいですか?・・なぁんてチェックできてしまう、というか。


元ネタ関連のどこかのコメントで、関数ポインタ的にはインターフェイスが足りないような、モヤモヤ...風なコメントを見た気がする(どこだったか探せなかったorz)のですが、それは多分ここら辺の話かな?と、思い蛇足です。


あと、今回のネタと関係ありますせんが、「オブジェクト指向入門には」OOP についてとても大事なことが書かれていて、特に、

クラスはモジュールであり、ソフトウェア分解の単位である。しかし、同時に型でもある(中略)。

オブジェクト指向という手法の能力の大部分は、このように識別したことに由来する。特に、継承はモジュールの拡張と型の特殊化の両方を提供するものとして見なければ完全に理解することはできない。

(強調はわたし)

は、本当に重要だけれど意外に知らない(意識していない)人が多いので、これを機会にちょっと布教活動。それぞれ「型継承(インターフェイス継承)」と「実装継承」と呼ばれています。型継承はポリモーフィズムのために行いますが、実装継承は差分プログラミングのために行います。

これが同時に起きるのは案外やっかいごとで、ダッグタイピングできない静的OOPLでは、継承は 型の継承 の目的で使おう、モジュールの拡張をしたいときは継承ではなく委譲を使おう・・というのが主流になっています。

Java の interface は、そういう良いプログラミングにプログラマを誘導するための言語機能ですね。

オブジェクト指向入門 第2版 原則・コンセプト (IT Architect’Archive クラシックモダン・コンピューティング)

オブジェクト指向入門 第2版 原則・コンセプト (IT Architect’Archive クラシックモダン・コンピューティング)