あなたの知っているOOPをすべて書き出しなさい(配点:5点)

オブジェクト指向でなぜ作るのか」以来、OOP が解らなくなってしまった三猫です。あーー、もう、わっかんない、と混乱のまっただ中にいる私にかけられた、sumim さんの優しい言葉。

とりあえず、ケイのメッセージングのOOとストラウストラップら(リスコフ、メイヤーなど)の抽象データ型のOOの要点について、みねこあさんなりの解釈を簡単でいいので箇条書きにでもしてもらうことはできますか? そこからすりあわせたほうがよいと思います。

http://d.hatena.ne.jp/minekoa/20080803#c1217824520

よーし! 箇条書きといわず、がんばっちゃうぞー。(と暴走する私。)

ストラウストラップのOOP

ストラウストラップの考える OOP 、本当は、What is.. 論文 に当たるのが正しい姿なのですが、今の私の脳内というと、実は申し訳ないことに「プログラミング言語 C++ 第3版」のイメージになっています。(ごめんなさい、その程度のワナビなんです)

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


こちらの「C++ひとめぐり」というのが、C++ が扱えるプログラミングスタイルについて、ざざっと説明していてわかりやすい・・というか印象に残ってしまう。

ざっと目次 + α を以下にまとめてます。

2 C++ひとめぐり
2.4 モジュラプログラミング
 ┌──────────────────────────────┐
 │必要なモジュールを決めよ                                    │
 │データがモジュールの中に隠蔽されるようにプログラムを分割せよ│
 └──────────────────────────────┘

2.5 データ抽象

    2.5.1 型を定義するモジュール        (偽の型)
    2.5.2 ユーザ定義型(ADT)
      ┌──────────────────────┐
      │使いたい型を決めよ                          │
      │個々の型に対して演算の完全なセットを提供せよ│
      └──────────────────────┘
    2.5.3 具象
    2.5.4 抽象型 (abstract => interfaceの分離の話)
        「この問題を解決するには、表現からインターフェイスを
          完全に切り離し純粋局所変数を諦めなければならない。」
    2.5.5 仮想関数

2.6 オブジェクト指向プログラミング
    「データ抽象は、優れた設計の基本要素であり、本書では一貫
      して設計の重点事項として扱い続ける。しかし、ユーザー定
      義型だけでは、プログラマの需要に応えられるだけの柔軟性
      に欠ける。本節では、純粋なユーザー定義型の問題点を示し
      てから、クラス階層を使ってその問題を解決する。」

    2.6.1 具象型の問題点
      (差分プログラミングしないと、同じコードのコピペになるよ、
       という話)

    2.6.2 クラス階層
      ┌───────────────────────┐
      │使いたい型を定めよ。                          │
      │個々の型に対して演算の完全なセットを提供せよ。│
      │継承をつかって共通点を明示的に示せ。          │
      └───────────────────────┘

2.7 ジェネリックプログラミング
    2.7.1 コンテナ
    2.7.2 汎用アルゴリズム


私はコレを読んだとき、素直に「OOPって継承のことだ」と思いました。そういう風にしかよめなかった。

Javaでいう インターフェイス をつかった抽象型については、「データ抽象」という項にいて、「オブジェクト指向プログラミング」の外の項であることが興味深いな、と思います。

後に「「抽象データ型のスーパーセットであるOOP」の言い回しを聞いて、そこの部分が OOP じゃなくって、前の段を包含して OOP なのだろうと 遅まきながら理解にいたるという。

ここらへんのもやもやは、そのまま取っておいて次に。

C++OOP

が、それじゃあちょっと生殺しなので。

C++OOP については、ちょうどC++ プライマー(第4版)のものがしっくり来るかな。

C++ プライマー 第4版 IT Architect’ Archive クラシックモダン・コンピューティング (IT Architects’ Archive―CLASSIC MODERN COMPUTING)

だいたいこんな感じ(要約。引用にあらず)

OOP の基になる基礎概念は3つある。

  • データ抽象化
  • 継承
  • 動的結合

継承と動的結合によってプログラムが二つの面ですっきりする

  1. 似た様なクラスの定義が簡単になる
  2. 似たようなクラスの違いの細部を無視してプログラムを書くのが簡単になる

データ抽象化は土台、部品。これに対し継承と動的結合は部品のつなぎ方。

3点セットを一応説明しているしていますが(そして、「カプセル化」や「クラス」ではなく、「データ抽象化」としている部分に素敵さを感じます)、そうはいいつつも「OO とは継承と動的結合である」と叫んでいる感じ。

C++ プライマーでは 多くの紙面を、クラス、またクラス、そして継承! といった調子の説明に割きながらも要所要所で、

15.1 OOP (オブジェクト指向プログラミング) : 概観

OOPの背後にある鍵となる考え方は多態性(polimorphism) である。polymorphism は「多くの形態」を意味するギリシャ語から導かれたものである。継承によって関連している型を多態的型という。多くの場合、派生型と基底型の「多くの形態」を区別しないで使うことが出来るからである。

と 多態の重要さも強調し、Is A や Has A の話や、抽象的インターフェイスといた点も「別世界の話」にしないというか。私の求めるモノであるので、好んで飲み込んでいるという贔屓目は否定できません。

メイヤー先生 の OOP

メイヤー先生の OOP 、、というかオブジェクト指向入門 の話なのです。ストラウストラップ先生がかなり置いてけぼり度が高い説明なのに対し、メイヤー先生はむちゃくちゃ言葉多く、丁寧に説明してくれるので好感度高しです。同じクラス指向の仲間でも、コチラはずっとわかりやすいと言った印象を持っています。

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

メイヤー先生の OOP というと、やはり金言は、「モジュールであり同時に型である、クラス」です。

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

で、

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

やん、格好いいです。ポイントここよ!

メイヤーセンセ、というかストラウストラップセンセもそうだけれど、OO に型を絡めて絡めて煮固めることで、分割統治した部品の、部品間の関係の正しさを静的にチェックしようとしています。再利用性の高く静的型チェックによる正しさの証明できる、そんなソフトウェアを目指しています。だから静的構想であるクラスが大切で、動的(実行時のorメモリ上の)構造であるオブジェクトは本質ではない、とするわけです。(ホログラフィック宇宙論みたいだぁね)

特にメイヤー先生は明確に「こうだ!」と打ち出す一方、他のOOPと称するものにも容赦なく...、とかSmalltalkとかSmalltalkとか、徹底的に dis られてます...orz

ちょっと、脱線

以下は今回のエントリに関係しない脱線ですが、メイヤー先生のことで大切なこと。2つ。

メイヤー先生の オブジェクト指向入門は、OOP の解説書の部分よりもむしろ、システムを分割し、良い構造をもたせるための 珠玉の「原理原則」が詰まっていることにこそ価値があると思います。open-closeの原則 とか 契約による設計とか。

これら「原理原則」は いつでも私たちにブレない方角を示してくれます。またその原則は、OOP と関係なしに役に立ったりするのです。そういう意味で、プログラマなら絶対読むべし。

もう一つ大事なことは、この本からメイヤー先生の言葉を引用するときには、注意しなくてはいけないことがああります。メイヤー先生はしばしば、データ、という意味でオブジェクトと言うこと、そして、モジュールとは単に構造化エンティティという意味で使っていていること。

特に後者は、極端には(欠点はあるとしても)サブルーチンのようなものであっても、モジュールと言うことに注意させないと迷い道にはまります。グローバル変数群とサブルーチンズ を固めたアレ に限定されるわけではないことです。


SmalltalkOOP

SmalltalkOOP が ケイの OOP ではないということに注意」と sumimさんはおっしゃっていますが、私の頭の中では、その差をまったく理解していない、というのが正直なところです(情けなや)。はっきり言えば、SmalltalkOOP しか知らないです。なのでその話を。

で、SmalltalkOOP が何かというと、オブジェクトとメッセージの世界です。

高速のネットワークで接続された小さな(しかし万能の)計算機の挙動にたとえられます。また、生命科学における細胞の営み

オブジェクト指向の概念の発明者は誰ですか?(改訂版) - Smalltalkのtは小文字です

というイメージであり、また、オブジェクトとメッセージがあれば クラスは実は OOP に本質的ではない要素だ、という考えを語るとき、我が身を Smalltalk海にドップリ沈めている感触なので、そういうイメージなのでしょう。

なんといっても脳に焼き付いているのが

In our experience, the SIMULA notion of class and instance is an outstanding metaphor for information structure. To describe processing, we have found the concept of message-sending to be correspondingly simple and general.

超訳: 経験上、クラスとインスタンスというSIMURAの概念は 情報構造のピカいちのメタファです。 同様に処理の表現においては、 メッセージ送信というコンセプトがシンプルかつ一般的であることを発見したのです。

http://users.ipa.net/~dwighth/smalltalk/St76/Smalltalk76ProgrammingSystem.html

の一文です。

SmalltalkOOP は、Simula が(階層概念のメタファはフォローした一方で)フォローしそこねた、オブジェクト間の協調のさせかたや、その責任の分担のさせかたの イメージのわきやすい「メタファ」を、新たに追加しました。それにより OOP の イメージのブレを抑えた点が素晴らしいと私は思います。

そして、メタファが導く通りに開発や思考を重ね、ソフトウェアの構造を突き詰めたところに 「SmalltalkOOP」があります。

そこからメタファを濾し取り除いて、残った液たるエッセンスは、「デザインパターン」やそれに類する オブジェクトのデザインのしかたとして、つまり OOP そのものの姿として広まっていきます。(既に具体的な姿があらわになっているので、そこに導いたメタファを取り除いても、その姿は揺らぎません)


SimulaのOOP?

Simula のクラス云々については、私は「階層的プログラミング構造」(Ole-Johan Dahl, C.A.R Hoare) に書いてあることしか知りません。

クラスとオブジェクトは、Algol 60 の ブロック を拡張(汎化?)したものです。ここで言う「ブロック」は C のブロックと同じです。Cでは実は {...} 毎に局所変数をもてます、というマニアックな事を知っている方にはしっくりきますが、そうでなければ、 サブルーチンと考えてもだいたいOKです。

Algol 60 のブロックは、

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

で、すでに実例(instance)を持っていますが

最近に起動されたブロックの実例が最初に消滅するという意味で,ブロックの実例の存在が入れ子構造をなす事を保証するように留意して言語の規則が設計されている.このことによって, ALGOL 60 の処理系では, 動的に記憶場所を割り当てて開放する方法としてスタック(stack)を用いることが出来る

という言う制約があります。これに対してその制約を取り払ったのが Simula の偉大なるお仕事。

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

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

この論文では、これ(↑)を使ったプログラミングのスタイルいろいろ模索しておりまして、それを 本エントリーでは Simula の OOP と勝手に呼ばせていただきます。

Simula のコレは OOP なのか?

この論文は 「構造化プログラミング」にダイクストラ先生の「構造化プログラミング論」と一緒に納められています。(皮肉というか、ソフトウェアの進化が段階的にすすんでいるんじゃない証拠というか)

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

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

この本は「プログラム構造化」をテーマに集められた論文集です。もちろんこの小論も例外でなく、

この小論では,プログラムを構造化するいくつかの方法を調べ,それらが概念の形成に関係していることを示す.

それぞれの概念は,必然的に,システムの限られた側面に関するものであり,全体のブログラムを分解(decomposition)して得られる一部分のプログラムに対応しているであろう.

有用な概念はどれも,ある程度の一般性をもつものである.すなわち,それは特殊な実例(instance)が集まったクラス(class)なのである.いい換えると,動的システムに現れる現象を,現象のクラスとしてひとまとめにし,それぞれのクラスをプログラム部分として記述しようというのである.

Simulaの構造化は、プログラムの構造化と概念をマッピングすることが特徴です。ブロックを汎化した新たな構造化エンティティにたいし、そのためのメタファ(「クラス」という名)を与えています。



そして、そのメタファにふさわしい機能も与えています。

という趣旨になっています。偉大なる発明か、はたまた悪魔の旅路か、クラスという新たな構造化エンティティをつかってプログラムを構造化する際に、その構造を概念へのマッピングすることを提案しています。

そして、そのメタファにふさわしい機能を クラスに与えています。概念の階層化です。

複雑な概念はそれを定義する単純な概念に従属する,という意味で,概念に階層をつけることになる.構成する手法は,プログラムを要素から組み立てる新しい方法であり, 連接(concatenation) といわれる.
連接は,2つのクラスAとB,あるいはクラスAとブロックCに対して定義される操作であり,新しいクラス,あるいはブロックを作る.連接は両方の所有物を合わせて1つにし,両方の動作を組み合わせるものである.連接されてできた対象の仮引数は,連接されるはじめの対象の仮引数に,後ろの対象の仮引数をつないだものである.

ようするに継承です。ちなみに仮引数..といっているのは、

クラスは,引数をもっていてももっていなくてもよく,手続きと全く同じ方法で宣言される.

(中略)

クラスの本体に局所的に宣言されている変数,手続き,および値呼びや参照呼びの仮引数はどれもそのクラスの所有物(attribute)であるという.

で、インスタンスフィールドだと思ってだいたいよし、というところ。


これが、後に型と一体化し、再び型と分離して考えられるようにしたほうが良さそうだ、と行き着くまでが、だいたい30年くらい?


* * *


さて、クラスは、元となったブロック同様 アルゴリズムの構造化部品であるのと同時に、データの構造か部品でもあって、その両方を等しく同時に構造化・抽象化することが出来ます。

制御の構造化におけるSimula メジャーな例は、やっぱり 離散的事象のシミュレーションと言うことになるでしょうか。一般にOOP の現実概念の投影能力の高さの例と引用されやすい「例」ですが、実際の肝は、オブジェクトが現実のモノを云々ではなく、ブロックのインスタンスが存在し続け、コール/リターンではない制御の受け渡しを出来るので、疑似平行プログラムを記述する能力を持っているということの方が、より大切なのではと思います。

平行しているプロセスを表現するために, 対応するプログラム要素が,計算機で多重プログラム(multiprogram)処理されなければならない,というわけではない.しかし,プログラムは,一時的に停止(中断)し,後で止まっていたところから再び実行出来ることが必要である.そこで動作している対象,すなわちシミュレーションにおける“プロセス”は,スケジュール機構 (時間割り当ての機構,scheduling mechanism) の制御のもとで,擬似的に平行して(in pseudo-parallel)働く (半) コルティンによって表現されるであろう.

SIMULA では,コルティンは,クラスの1つの対象で表される.


* * *


正直ここまで書いてあれば、「Simula は たまたま後から見れば OOP 出来る能力を満たしていた」ではなく、「Simula の時点で 後に OOP と呼ばれることになるモノは 発明された」、と思いたくなってきます。

この後 ADT を混ぜられたり、メッセージという新しいメタファを追加されたり、好き勝手いじくられ発散していくOOP が、後にやっぱり何か1つの概念に収斂されていくのは、Simula の OOP の時点で、そのコアが出来ていたから、という風な考えは魅力があります。

クックの OOP

sumimさんの紹介により存在をしった、クックのOOP ですが、実はいまだによく解りません。(^^;

モヤモヤっとわかったような、それでいてわからないような。以前、sumim さん に親切丁寧に教えていただいたのですが、それでもこのポンコツ頭は処理できなかった様子。
エンラエンラのまま今に至ります。

後述の「私の考えるOOP」にオレオレでない後ろ盾が欲しかったので、とても理解したかったのですが、現実は厳しいです...orz

私は OOP をどのようなモノと思っているか。

いよいよ大詰め。

先日の なぜオブ の書評について、「なぜオブが クラス指向な抽象データ型のOO だとすれば、批判点は適切ではないのでは」と言われると、否定はちょっと難しくなります。*1しかし、それでも批判したいのは、なぜオブ本の OOP の延長上にあるものでは、現実の問題が解決できない、そんな直感アラームがガンガン鳴り響いているからです。

じゃあ、現実の問題が解決できる、役に立つ OOP ってなんじゃろ? となると、OOPって何?

OOPって、実際のトコロ デザインパターンみたいなプログラムをつくること じゃね?と思っていいます。(あぁ、オレオレかしらん)


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

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

もちろん OOPデザインパターンだ、と言いたいわけじゃなくって、OOP で作られるプログラムの解りやすい例として デザインパターンがあって、ようするに「責務分散協調系としてシステムを描く」のが OOP 、と言う風に思っています。


実際、「メッセージなんてOOにはない」とか、「継承とクラスがなくちゃ OOじゃないというのは間違いだ」という、それぞれの陣営の土台を全否定する話はよーーーく、耳にするのですが、「デザインパターンのような設計はOOPではない、邪道だ」なんて声はそれに比べて弱いですし、

もーみんな取り入れちゃってるし(w



ストラウストラップの OO は、デザインパターンのような設計と あまりなじまないと感じます。デザインパターンのような設計は、

┌──────────────────────────────┐
│必要なモジュールを決めよ                                    │
│データがモジュールの中に隠蔽されるようにプログラムを分割せよ│
└──────────────────────────────┘
                      ↓
┌──────────────────────┐
│使いたい型を決めよ                          │
│個々の型に対して演算の完全なセットを提供せよ│
└──────────────────────┘
                      ↓
┌───────────────────────┐
│使いたい型を定めよ。                          │
│個々の型に対して演算の完全なセットを提供せよ。│
│継承をつかって共通点を明示的に示せ。          │
└───────────────────────┘

OOP だぞ!、という風なものとは異質に感じます。ストラウストラップセンセの教えそのものの是非はおいといても、その説明を不注意に扱えば、悪い設計指針以外の何者でもなくなってしまうことは、もはや自明の理だとおもっていますがどうでしょう。

そして、個人的な経験のお話なのですが、正直ストラウストラップ先生の教えを基に、上手いプログラムを書くことは、私には大変難しいことでした。この生き方はダメです!と思ってしまったのも無理がないと自分で自分を慰めてみるテスト...




GoFデザインパターンの序文には

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

(強調は私)


そう、そうなんですよ!

C++ な古典的OOP でクラス階層を一生懸命もてあそんだところでちっともうまく行かない。ちっとも現実の問題を解決出来ない...orz、と、さんざ苦しんだところ、デザインパターンを知ったスッキリ感にこのような感動を覚えた方は多いハズです。正直にいいうと「ああ、これが本物のOOPかぁ」と思いましたし、今も実はそう思っています(オレオレ風ふかせてゴメンです(^^;)

クックのOOP の理解を私は欲したのは、この責務分散協調系なOOP を、オレオレじゃないものとする後ろ盾が欲しかったからです。(でもわかんなかった)



うーん、うまく言えないなぁ。人の言葉を借りてしまいます。「OOP とは何か」の「何」について言いたいことは最近もらった本: インターフェイス指向設計 -steps to phantasien さんのエントリのような内容で、(継承に殺意を覚えている部分まで含めてw)、心の底から同意です。

けれど実際の価値ある複雑な仕事は, その多くを複数のオブジェクトが担っている. 利用者からは隠されているだけだ. 困ったことに, なぜか複雑さは教科書の読者からも隠されてしまう. それがまさに知りたいことなのに! 実装の詳細というには話がでかすぎる.

最近もらった本: インターフェイス指向設計 - Backnumbers: Steps to Phantasien

実際のソフトウェアでは, 複数のオブジェクトが協調して仕事を進めることになる. だからどう仕事を分担し, 協調して振る舞うべきなのかを考えないと, 良い抽象をつくることはできない.

最近もらった本: インターフェイス指向設計 - Backnumbers: Steps to Phantasien


デザインパターンは、こういう姿の具体例を見せてくれるから、アハッとなりやすいと言う点で良いモノだと思います。


OOP ってなんなのさ / どうしてこんな事になっちゃってるのさ

注意:以下は妄言です。

この 「今時のOOP」とはいったい何なのでしょうか。デザインパターンSmalltalk の星からやってきたみたい。だから SmalltalkOOP? うーん、それはどうかな。

たしかに、「今時のOOP」と、たとえば憂鬱本(1998年発行)で描かれているような OOP の姿は全く違う形をしていますが、1996年発行の サクサクSmalltalk で描かれている OOP の姿は、大きく違わない。*2


だけれど、責務を分散し協調して仕事をする系 を描くプログラミングスタイル という OOP は、それは sumimさんの言うもう一翼のOOP――「ADTのOOP」には無かったものなのでしょうか。それとも、あったけれども、適切な「OOPで作られた良いプログラム」のイメージを多くのプログラマに与えられなかった結果、愚民プログラマが勝手に間違ったOOP像を描いてしまったということなのでしょうか。


Simula の「階層的プログラミング構造」を読むと、なんとなく、オブジェクトの協調関係の組み方についても包含しているような気がしてきますし*3、メイヤー先生の「原理原則」は、「今時のOOP」の親和性はとても高いです。OOP は、Simula の最初の時から、OOPは 概念というヒトの抽象化の武器をよりどころに、責務分散協調系をうまく抽象化することだったのではないでしょうか。

じゃあ、なぜ Smalltalk の側が「デザインパターンの宝庫」だったのか。それは一重に良いメタファを持っていたからじゃないのか。

ADTのOOP は モジュールの組み合わせ方を型チェックする 合わせ技で欲張った副作用として、その敷衍がうまくいかなくなってしまったのではないか。(Simula のクラスは、(自信がないけれど)ADT の発展ではないし、まだADTとコネコネされていないと思う。(混ぜたのはC++?))

などなど。



すっきりしないなぁ。sumim さんみたいに、ターンA の悟りを開かないとこのモヤモヤはとれないのかしら。


* * *


さて、採点は如何に?

*1:それにしたって変なのは変なのだけれど、その変さをうまく説明出来る自身がないです

*2:にも関わらず、憂鬱本SmalltalkJava も同じだよ、風な文言がちりばめられているのだから、私は つい、一生懸命勉強してかいてあるけれど、結果的に不勉強な内容な本だと断じてしまう。それは作者の怠慢じゃなくって高速道路の未整備のせいかもしれないとか オレオレ理論を展開してしまったのです。

*3:ずばりと書いていないので、「そう読み取りたい」という私の妄想かも、と思う