「オブジェクト指向プログラミング」の版間の差分
編集の要約なし |
用語と解説 |
||
(同じ利用者による、間の17版が非表示) | |||
8行目: | 8行目: | ||
'''オブジェクト指向プログラミング'''(オブジェクトしこうプログラミング、{{Lang-en-short|''object-oriented programming''}}、略語:OOP)とは、互いに密接な関連性を持つ[[変数 (プログラミング)|データ]]と[[メソッド (計算機科学)|メソッド]]をひとつにまとめて[[オブジェクト (プログラミング)|オブジェクト]]とし、それぞれ異なる性質と役割を持たせたオブジェクトの様々な定義と、それらオブジェクトを相互に作用させる様々なプロセスの設定を通して、プログラム全体を構築するソフトウェア開発手法である。 |
'''オブジェクト指向プログラミング'''(オブジェクトしこうプログラミング、{{Lang-en-short|''object-oriented programming''}}、略語:OOP)とは、互いに密接な関連性を持つ[[変数 (プログラミング)|データ]]と[[メソッド (計算機科学)|メソッド]]をひとつにまとめて[[オブジェクト (プログラミング)|オブジェクト]]とし、それぞれ異なる性質と役割を持たせたオブジェクトの様々な定義と、それらオブジェクトを相互に作用させる様々なプロセスの設定を通して、プログラム全体を構築するソフトウェア開発手法である。 |
||
'''[[オブジェクト指向]]'''という用語自体は、計算機科学者[[アラン・ケイ]]によって生み出されている。 |
'''[[オブジェクト指向]]'''という用語自体は、計算機科学者[[アラン・ケイ]]によって生み出されている。1962年公開の言語「[[Simula]]」の設計に印象を受けたケイが咄嗟に口にしたとされるこの造語は、彼が1972年から公開を始めた「[[Smalltalk]]」の言語設計を説明する中で初めて世間に発信された。なお、ケイが示した[[メッセージパッシング]]を中心にするオブジェクト指向は広く認知される事はなく、[[オブジェクト (プログラミング)|オブジェクト]]というプログラム概念を注目させるだけに留まっている。同時にケイの手から離れたオブジェクト指向は[[抽象データ型]]を中心にした解釈へと推移していき、1983年に計算機科学者[[ビャーネ・ストロヴストルップ]]が公開した「[[C++]]」が契機になって、日本では一般にOOPの三大要素と呼ばれる[[カプセル化]]、[[継承 (プログラミング)|継承]]、[[ポリモーフィズム|多態性]]といった[[プログラミングパラダイム|パラダイム]]が確立されている。 |
||
== 特徴 == |
== 特徴 == |
||
現行のオブジェクト指向プログラミングは、1974年に計算機科学者[[バーバラ・リスコフ]]らが提唱した[[抽象データ型]]を基礎的な考え方にする方向性で定着している。[[抽象データ型]]のプログラム実装スタイルを具体的に規定したものが1~3であり、日本では一般に三大要素と呼ばれている。これに沿った言語仕様を備えたプログラミング言語がオブジェクト指向準拠と判別されている。4 |
現行のオブジェクト指向プログラミングは、1974年に計算機科学者[[バーバラ・リスコフ]]らが提唱した[[抽象データ型]]を基礎的な考え方にする方向性で定着している。[[抽象データ型]]のプログラム実装スタイルを具体的に規定したものが1~3であり、日本では一般に三大要素と呼ばれている。これに沿った言語仕様を備えたプログラミング言語がオブジェクト指向準拠と判別されている。4は[[アラン・ケイ]]が重視する元祖的なコンセプトであり、オブジェクト指向の源流思想として蛇足ながら紹介を加える。 |
||
#[[カプセル化]](''encapsulation'') |
#[[カプセル化]](''encapsulation'') |
||
17行目: | 17行目: | ||
#[[ポリモーフィズム|多態性]](''polymorphism'') |
#[[ポリモーフィズム|多態性]](''polymorphism'') |
||
#[[メッセージ (コンピュータ)|メッセージパッシング]](''message passing'') |
#[[メッセージ (コンピュータ)|メッセージパッシング]](''message passing'') |
||
#[[ダイナミックバインディング|遅延バインディング]](''late binding'') |
|||
=== カプセル化 === |
=== カプセル化 === |
||
一定の関連性を持つデータ(変数、プロパティ、フィールド)と、それらを操作するメソッド(関数)をひとまとめにしてオブジェクトとし、外部に対して必要とされるデータとメソッドのみを公開し、それ以外を内部に隠蔽する仕組みがカプセル化と呼ばれる。公開されたデータは外部のメソッドから直接参照ないし変更する事できる。公開されたメソッドは外部のメソッドから直接呼び出す事ができる。隠蔽されたデータとメソッドは外部からアクセスできず、これは{{仮リンク|情報隠蔽|en|information hiding}}と呼ばれる。メソッドを通してデータを参照ないし変更する仕組みはデータの抽象化を表現する。データを参照するメソッドはゲッターまたはアクセッサ |
一定の関連性を持つデータ(変数、プロパティ、フィールド)と、それらを操作するメソッド(関数)をひとまとめにしてオブジェクトとし、外部に対して必要とされるデータとメソッドのみを公開し、それ以外を内部に隠蔽する仕組みがカプセル化と呼ばれる。公開されたデータは外部のメソッドから直接参照ないし変更する事できる。公開されたメソッドは外部のメソッドから直接呼び出す事ができる。隠蔽されたデータとメソッドは外部からアクセスできず、これは{{仮リンク|情報隠蔽|en|information hiding}}と呼ばれる。メソッドを通してデータを参照ないし変更する仕組みはデータの抽象化を表現する。データを参照するメソッドはゲッターまたはアクセッサと呼ばれる。データを変更するメソッドはセッターまたはミューテイタと呼ばれる。 |
||
=== 継承 === |
=== 継承 === |
||
26行目: | 25行目: | ||
=== 多態性 === |
=== 多態性 === |
||
異なる種類のオブジェクトに同一の操作インターフェースを持たせる仕組みが多態性と呼ばれる。オブジェクト指向視点の多態性は、クラスの派生関係またはオブジェクトの動的バインディングによって、コンパイル時のメソッド名から呼び出されるプロセス内容が実行時に決定される |
異なる種類のオブジェクトに同一の操作インターフェースを持たせる仕組みが多態性と呼ばれる。オブジェクト指向視点の多態性は、クラスの派生関係またはオブジェクトの動的バインディングによって、コンパイル時のメソッド名から呼び出されるプロセス内容が実行時に決定される仕組みを意味する{{仮リンク|サブタイプ多相|en|subtyping|label=}}を指す。オブジェクト指向のサブタイプ多相はクラスベースの{{仮リンク|仮想関数(OOP)|en|Virtual function|label=仮想関数}}と、プロトタイプベースの{{仮リンク|動的ディスパッチ|en|Dynamic dispatch|label=}}の二手法に大別される。仮想関数は、メソッドが所属するクラスの派生関係のみに焦点を当てた単一ディスパッチであり、スーパークラス抽象メソッドへの呼び出しから、それを[[オーバーライド]]したサブクラス実装メソッドに分岐させる機能を指す。その際は[[関数へのポインタ|各メソッドへのポインタ]]を並べた[[Vtable|仮想関数テーブル]]と呼ばれる仕組みが用いられる。単一ディスパッチとはプロセス分岐に関与するオブジェクトが一つであることを意味しており、二つ以上の場合は[[多重ディスパッチ]]になる。多重の方はメソッドが属するクラスの派生関係だけでなく、そのメソッドの各引数のクラスの派生関係にも注目した形態であり、各引数は実行時に[[ダウンキャスト|型ダウンキャスト]]されてそれらの引数型の組み合わせに対応したプロセスに分岐する。メソッドが属するクラスの派生関係が絡まない場合は単一引数だと単一ディスパッチになる。{{仮リンク|動的ディスパッチ|en|Dynamic dispatch|label=}}は、[[プロトタイプベース]]のオブジェクトのメソッド名スロットに当てはめられるメソッド実装の参照が随時切り替えられることで、そのメソッド名から呼び出されるプロセスが実行時に決定されるという仕組みを指す。[[クラスベース]]の方では[[リフレクション (情報工学)|リフレクション]]機能によって同様に、メソッド名から呼び出されるプロセス内容が実行時に決まるという仕組みが実装される。 |
||
=== メッセージパッシング === |
=== メッセージパッシング === |
||
{{Quotation|''I thought of objects being like biological cells and/or individual computers on a network, only able to communicate with messages.''<br>(さながら生物の細胞、もしくはネットワーク上の銘々のコンピュータ、それらはただメッセージによって繋がり合う存在、僕はオブジェクトをそう考えている)|Alan Kay}}{{Quotation|''... each object could have several algebras associated with it, and there could be families of these, and that these would be very very useful.''<br>(銘々のオブジェクトは自身に伴う幾つかの「代数」を持つ、またそれらの家族たちもいるかもしれない、それらは極めて有用になるだろう)|Alan Kay}}{{Quotation|''The Japanese have a small word - ma ... The key in making great and growable systems is much more to design how its modules communicate rather than what their internal properties and behaviors should be.''<br>(日本語には「間」という言葉がある・・・成長的なシステムを作る鍵とは内部の特徴と動作がどうあるべきかよりも、それらがどう繋がり合うかをデザインする事なんだ)|Alan Kay}}{{Quotation|''I realized that the cell/whole-computer metaphor would get rid of data,'' ...<br>(僕はこう気付いた、細胞であり全体でもあるコンピュータメタファーはデータを除去するであろうと、)|Alan Kay}}{{Quotation|''... there were two main paths that were catalysed by Simula. The early one (just by accident) was the bio/net non-data-procedure route that I took. The other one, which came a little later as an object of study was abstract data types, and this got much more play.''<br>(Simulaを触媒にした二本の道筋があった。初めの一本はバイオネットな非データ手法、僕が選んだ方だ。少し遅れたもう一本は抽象データ型、こっちの方がずっと賑わってるね。)|Alan Kay}} |
|||
{{Quotation|''I thought of objects being like biological cells and/or individual computers on a network, only able to communicate with messages.'' |
|||
(さながら生物の細胞、もしくはネットワーク上の銘々のコンピュータ、それらはただメッセージによって繋がり合う存在、僕はオブジェクトをそう考えている)|Alan Kay}}{{Quotation|''... each object could have several algebras associated with it, and there could be families of these, and that these would be very very useful.'' |
|||
(銘々のオブジェクトは自身に伴う幾つかの「代数」を持つ、またそれらの家族たちもいるかもしれない、それらは極めて有用になるだろう)|Alan Kay}}{{Quotation|''The Japanese have a small word - ma ... The key in making great and growable systems is much more to design how its modules communicate rather than what their internal properties and behaviors should be.'' |
|||
(日本語には「間」という言葉がある・・・成長的なシステムを作る鍵とは内部の特徴と動作がどうあるべきかよりも、それらがどう繋がり合うかをデザインする事なんだ)|Alan Kay}} |
|||
=== 遅延バインディング === |
|||
{{Quotation|''I realized that the cell/whole-computer metaphor would get rid of data,'' ... |
|||
(僕はこう気付いた、細胞であり全体でもあるコンピュータメタファーはデータを除去するであろうと、)|Alan Kay}}{{Quotation|''... there were two main paths that were catalysed by Simula. The early one (just by accident) was the bio/net non-data-procedure route that I took. The other one, which came a little later as an object of study was abstract data types, and this got much more play.'' |
|||
(''Simula''を触媒にした二本の道筋があった。初めの一本は細胞組織的な非データ手法、僕が選んだ方だ。少し遅れたもう一本は抽象データ型、こっちの方がずっと賑わってるね。)|Alan Kay}} |
|||
== 歴史 == |
== 歴史 == |
||
1954年に初の[[高水準言語]]・[[FORTRAN]]が登場すると、開発効率の劇的な向上と |
1954年に初の[[高水準言語]]・[[FORTRAN]]が登場すると、開発効率の劇的な向上と共にソフトウェア要求度も自然と高まりを見せてプログラム規模の急速な拡大が始まった。それに対応するために肥大化したメインルーチンを[[サブルーチン]]に分割する手法と、[[スパゲティプログラム|スパゲティ化]]した[[Goto文|goto命令]]を[[制御構造|制御構造文]]に置き換える手法が編み出され、これらは1960年に公開された言語「[[ALGOL|ALGOL60]]」で形式化された。当時のALGOLは[[アルゴリズム]]記述の一つの模範形と見なされたが、それと並行して北欧を中心にした計算機科学者たちはより大局的な観点によるプログラム開発技法の研究を進めていた。 |
||
=== Simulaの開発(1962~72) === |
|||
1962年、ノルウェー計算センターで[[モンテカルロ法]]シミュレーションを運用していた計算機科学者[[クリステン・ニゴール]]は、[[ALGOL|ALGOL60]]を土台にしてProcessと呼ばれる[[コルーチン]]機構を加えたプログラミング言語「[[Simula]]」を公開し、続けてその拡張にも取り組んだ。ニゴールの同僚で、1963年にSimulaを[[メインフレーム|汎用機]][[UNIVAC I|UNIVAC]]系統上で運用できるように実装した計算機科学者[[オルヨハン・ダール]]は、Processにローカル変数構造を共有する複数の手続き(サブルーチン)を加えてパッケージ化する言語仕様を考案した。程なくしてALGOL60コンパイラに準拠していての限界を悟ったニゴールとダールは、1965年からSimulaを一から再設計するように方針転換した。その過程で彼らは、計算機科学者[[アントニー・ホーア]]が考案して1962年のSIMSCRIPT([[FORTRAN]]用のスクリプト)に実装していたRecord Classを参考にしている。Record Classはソースコード水準の抽象表現を、各[[メインフレーム|汎用機]]に準拠した[[マシンコード]]水準の実装符号に落とし込む段階的データ構造のプログラム概念であった。これをモデルにした[[継承 (プログラミング)|継承]]とその構造上に成り立つ仮想手続き(仮想関数)の仕組みも考案され、この両機能を備えたProcessのパッケージ化を「[[クラス (コンピュータ)|クラス]]」とし、クラスをメモリに展開したものを「[[オブジェクト (プログラミング)|オブジェクト]]」とする言語仕様がまとまり、1967年に「[[Simula|Simula67]]」が初公開された。オブジェクトという用語は、[[MIT]]の計算機科学者[[アイバン・サザランド]]が1963年に開発した[[Sketchpad]]([[CAD]]と[[GUI]]の元祖)の設計内にあるObjectが先例であった。Simula67コンパイラはまず[[UNIVAC I|UNIVAC]]上で運用され、翌年から汎用機[[バロース B5000|バロースB5500]]などでも稼働されて北欧、ドイツ、ソ連の各研究機関へと広まり、1972年には[[IBMメインフレーム|IBM汎用機]][[System/360]]などにも導入されて北米全土にも広まった。その主な用途は物理シミュレーションであった。 |
|||
=== 構造化プログラミングの提唱(1969~75) === |
|||
1962年、ノルウェー計算センターで[[モンテカルロ法]]シミュレーションを運用していた計算機科学者[[クリステン・ニゴール]]は、[[ALGOL|ALGOL60]]をモデルにしたプログラミング言語「[[Simula]]」を公開し、続けてその拡張にも取り組んだ。ニゴールの同僚で、Simulaを[[メインフレーム|汎用機]][[UNIVAC I|UNIVAC]]系統上で運用できるように実装した計算機科学者[[オルヨハン・ダール]]は、手続き(サブルーチン)をパッケージ化する言語仕様を考案した。程なくしてALGOL60コンパイラに準拠していての限界を悟ったニゴールとダールは、1965年からSimulaを一から再設計するように方針転換した。その過程で両名は、計算機科学者[[アントニー・ホーア]]が考案して1962年のSIMSCRIPT([[FORTRAN]]用のスクリプト)に実装していたRecord Classを模範にした。Record Classはソースコード水準の抽象表現を、各[[メインフレーム|汎用機]]に準拠した[[マシンコード]]水準の実装符号に落とし込む段階的データ構造のプログラム概念であった。彼らの構想は、[[継承 (プログラミング)|継承]]と仮想関数を備えた[[クラス (コンピュータ)|クラス]]と、それをメモリに展開した[[オブジェクト (プログラミング)|オブジェクト]]という言語仕様にまとめられて、1967年に「[[Simula|Simula67]]」が初公開された。オブジェクトという用語は、[[MIT]]の計算機科学者[[アイバン・サザランド]]が1963年に開発した[[Sketchpad]]([[CAD]]と[[GUI]]の源流)の設計内にあるObjectが先例であった。Simula67コンパイラはまず[[UNIVAC I|UNIVAC]]上で運用され、翌年から汎用機[[バロース B5000|バロースB5500]]などでも稼働されて北欧、ドイツ、ソ連の各研究機関へと広まり、1972年には[[IBMメインフレーム|IBM汎用機]][[System/360]]などにも導入されて北米全土にも広まった。その主な用途は物理シミュレーションであった。 |
|||
[[Simula]]の普及と前後して1960年代半ばになると、プログラム規模の際限ない肥大化に伴う開発現場の負担増大が顕著になり、いわゆる[[ソフトウェア危機]]問題が計算機科学分野全般で取り沙汰されるようになった。その解決に取り組んだ計算機科学者[[エドガー・ダイクストラ]]は、1969年のNATOソフトウェア工学会議で「[[構造化プログラミング]]」という論文を発表し[[トップダウン設計とボトムアップ設計|トップダウン設計]]、段階的な[[抽象化 (計算機科学)|抽象化]]、階層的な[[モジュール化]]、共同詳細化といった構造化手法を提唱した。ダイクストラの言う構造化とは開発効率を高めるための[[分割統治法]]を意味していた。なおこの構造化プログラミングは後に曲解されて[[制御構造|制御構造文]]を中心にした解釈の方で世間に広まり定着している。共同詳細化は抽象データ構造を専用サブルーチンを通して扱うという概念である。これはSimulaの手続きを通してクラス内の変数にアクセスするという仕組みをモチーフにしていた。段階的な抽象化と階層的なモジュール化は時系列的にも、SIMSCRIPTの段階的データ構造と、Simura67の継承による階層的クラス構造を模倣したものであった。[[エドガー・ダイクストラ|ダイクストラ]]、[[アントニー・ホーア|ホーア]]、[[オルヨハン・ダール|ダール]]の三名は1972年に『構造化プログラミング』と題した共著を上梓していることから互いの研鑽関係が証明されている。その階層的プログラム構造という章の中でダールは、Simulaの目指した設計を更に明らかにした。{{Quotation|''influenced by Sketchpad, Simula, the design for the ARPAnet, the Burroughs B5000, and my background in Biology and Mathematics, I thought of an architecture for programming.'' |
|||
<br>([[Sketchpad]]、[[Simula]]、[[アーパネット]]、[[バロース B5000|バロースB5000]]、それと専攻していた生物学と数学に影響されて僕はプログラミングアーキテクチャを思索していた)|Alan Kay}}1974年に[[MIT]]の計算機科学者[[バーバラ・リスコフ]]とステファン・ジルは「[[抽象データ型]]」というプログラム概念を提唱した。彼女らの理論は、ダイクストラが提示したモジュールの共同詳細化を、[[セマンティクス|振る舞い意味]]によって定義される抽象データという考え方でより明解に形式化し、データ階層ないしモジュール階層の連結関係を、[[上位概念、下位概念、同位概念および同一概念|上位概念と下位概念]]の[[リスコフの置換原則|置き換え原則]]で明確に標準化した。一方、1970年に構造化言語[[Pascal]]を開発していた計算機科学者[[ニクラウス・ヴィルト]]は、ダイクストラによる共著出版後の1975年にモジュール化言語[[Modula-2|Modula]]を提示してモジューラプログラミングというパラダイムを生み出している。このようにいささか奇妙ではあるが、Simulaのクラスとオブジェクトというプログラム概念は、巷で言われる構造化からモジュール化へといった進化の流れとは関係なく、しかもその前段階においてさながら彗星のように生まれたパラダイムであった。 |
|||
=== Smalltalkとオブジェクト指向の誕生(1972~81) === |
|||
'''構造化プログラミングの提唱(1969~1978年)''' |
|||
初代SimulaからのProcessの仕様は、[[パロアルト研究所]]の計算機科学者[[アラン・ケイ]]によるオブジェクトと「メッセージ」というプログラム概念のヒントになった。ケイはプログラム内のあらゆる要素をオブジェクトとして扱い、オブジェクトはメッセージの送受信でコミュニケーションするという独特のプログラム理論を提唱した。メッセージとはプログラムコードとしても解釈できるデータ列のことであり、そのデータ列を評価(''eval'')することで新たなデータを導出できるという仕組みを意味していた。抽象データを扱うサブルーチンを更に抽象データ化したようなスタイルである。オブジェクトが受け取ったメッセージは任意のタイミングで評価できるので非同期通信、単方向通信(送りっぱなし処理)をも可能にしていた。この発想の背景には[[LISP]]の影響があった。オブジェクトとメッセージの構想に基づいて開発された「[[Smalltalk]]」はプログラミング言語と[[GUI]]運用環境を併せたものとなり、1972年に[[Alto|ゼロックスAlto]]上で初稼働された。Smalltalkの設計を説明するためにケイが考案した「[[オブジェクト指向]]」という用語はここで初めて発信された。またメッセージの構想は[[MIT]]の計算機科学者[[カール・ヒューイット]]に能動的な[[プロセス代数]]を意識させて、1973年発表の[[アクターモデル]]のヒントにもなっている。しかし、データ列が常にコード候補として扱われる処理系は、当時のコンピュータには負荷が大きく実用的な速度を得られないという問題にすぐ直面した。Smalltalk-74とSmalltalk-76の過程で、やむなくメッセージはセレクタ仕様の追加と共に構想通りの評価ができないほどシステム向けに最適化され、レシーバーは動的ディスパッチとメソッド仕様が中心になり、オブジェクトはクラス定義の存在感が大きくなった。{{Quotation|''Smalltalk is not only NOT its syntax or the class library, it is not even about classes. I'm sorry that I long ago coined the term "objects" for this topic because it gets many people to focus on the lesser idea.The big idea is "messaging".'' |
|||
[[Simula]]の普及と前後して1960年代半ばになると、プログラム規模の際限ない肥大化に伴う開発現場の諸問題が顕著になり、いわゆる[[ソフトウェア危機]]が計算機科学分野全般で取り沙汰されるようになった。[[ソフトウェア危機]]問題の解決に取り組んだ計算機科学者[[エドガー・ダイクストラ]]は、1969年のNATOソフトウェア工学会議で「[[構造化プログラミング]]」という論文を発表し、その中で[[トップダウン設計とボトムアップ設計|トップダウン設計]]、段階的な[[抽象化 (計算機科学)|抽象化]]、階層的な[[モジュール化]]、統合詳細化といった構造化手法を提唱した。プログラムを構造化すればその規模に関わらず[[正当性 (計算機科学)|正当性]]の証明が可能になるというのが論文の主張であった。統合詳細化は抽象データ構造を専用サブルーチンを通して扱うという概念である。段階的な抽象化と階層的なモジュール化は時系列的に、SIMSCRIPTの段階的データ構造と、Simura67の継承による階層的クラス構造に倣っていると見て差し支えないものである。この[[エドガー・ダイクストラ|ダイクストラ]]、[[アントニー・ホーア|ホーア]]、[[オルヨハン・ダール|ダール]]の三名は1972年に『構造化プログラミング』と題した共著を上梓している。その階層的プログラム構造という章の中でダールは、Simulaの目指した設計を更に明らかにした。1974年に計算機科学者[[バーバラ・リスコフ]]とステファン・ジルは「[[抽象データ型]]」というプログラム概念を提唱した。その中でダイクストラが提示したモジュールの統合詳細化は、[[セマンティクス|振る舞い]]によって定義される抽象データという考え方でより明解に形式化され、データ階層ないしモジュール階層の連結関係は[[上位概念、下位概念、同位概念および同一概念|上位概念と下位概念]]の[[リスコフの置換原則|置き換え原則]]の確立によって明確に標準化された。一方、1970年に構造化言語[[Pascal]]を開発していた計算機科学者[[ニクラウス・ヴィルト]]はダイクストラの理論を参考にした上で、モジュール化言語[[Modula-2]]を1978年に公開しモジューラプログラミングというパラダイムを生み出している。このようにいささか奇妙ではあるが、Simulaのクラスとオブジェクトというプログラム概念は、巷で言われる構造化からモジュール化へといった進化の流れとは関係なく、しかもその前段階においてさながら彗星のように生まれたパラダイムであった。 |
|||
<br>(Smalltalkはその構文やライブラリやクラスをも関心にしていないという事だけではない。多くの人の関心を小さなアイディアに向かせたことから、僕はオブジェクトという用語を昔作り出したことを残念に思っている。大切なのはメッセージングなんだ。)|Alan Kay}}1980年のSmalltalk-80は、元々はメッセージを重視していたケイを自嘲させるほど同期的で双方向的で手続き的なオブジェクト指向へと変貌していた。それでも動的ディスパッチと[[委譲]]でオブジェクトを連携させるスタイルは画期的であり、1994年に発表される[[デザインパターン (ソフトウェア)|デザインパターン]]の模範にもされている。1981年に大手専門誌[[Byte (magazine)|BYTE Magazine]]がSmalltalkとケイ提唱のオブジェクト指向を紹介して世間の注目を集める契機になったが、ケイの思惑に反して技術的関心を集めたのはクラス機構の方であった。オブジェクト指向は知名度を得るのと同時に、Simula発の[[クラス (コンピュータ)|クラス]]とそれを理論面から形式化した[[抽象データ型]]を中心に解釈されるようになり、それらの考案者がケイの構想とは無関係であったことから、オブジェクト指向の定義はケイの手を離れて独り歩きするようになった。 |
|||
=== C++の開発(1979~86) === |
|||
'''Smalltalkとオブジェクト指向の誕生(1972~1980年)''' |
|||
[[Simula]]を研究対象にしていた[[ベル研究所|AT&Tベル研究所]]の計算機科学者[[ビャーネ・ストロヴストルップ]]は、1979年からクラス付きC言語の開発に取り組み、1983年に「[[C++]]」を公開した。C++で実装された[[クラス (コンピュータ)|クラス]]は、Simula譲りの[[継承 (プログラミング)|継承]]と仮想関数に加えて、モジューラプログラミングのデータ隠蔽をモデルにしたアクセスコントロールを備えていた。C++で確立されたアクセスコントロールはカプセル化の元になったがコードスタイル上ほとんどザル化されており、その理由からストロヴストルップ自身もC++は正しくない(''not just'')オブジェクト指向言語であると明言している。1986年にソフトウェア技術者[[バートランド・メイヤー]]が開発した「[[Eiffel]]」の方は、正しいオブジェクト指向を標榜してクラスのカプセル化を遵守させるコードスタイルが導入されていた。クラスメンバは属性、手続き、関数の三種構成で、手続きで属性を変更し関数で属性を加工参照するという形式に限定されており、これは抽象データ型の[[セマンティクス|振る舞い意味論]]に沿った実装であった。アクセスコントロールはC++のアクセス修飾子による段階的スコープ定義に対して自身のクライアントクラスを定義する書式になり、また[[契約による設計]]に沿ったきめ細かなアサーション機能が備えられていた。前者は結合度、後者は凝集度の面からカプセル化を補強した。C++の仮想関数は延期関数の名で実装された。{{Quotation|''I made up the term ‘object-oriented’, and I can tell you I didn’t have C++ in mind.'' |
|||
<br>(僕はオブジェクト指向という言葉を作った、それとC++に関心がなかったことも分かっている)|Alan Kay}}1986年から[[Association for Computing Machinery|ACM]]は[[OOPSLA|オブジェクト指向会議]](OOPSLA)を開催し、そのプログラミング言語セクションではクラス・パラダイムのオブジェクト指向の意見交換が中心になされ、Eiffelを現行の模範形とする声が多く上がった。しかし世間のプログラマの間では厳格なEiffelよりも、柔軟で融通の利くC++の人気の方が高まっていた。この頃に専用サブルーチンを通したデータ抽象とアクセスコントロールの概念はカプセル化という用語に一般化され、仮想関数ないし延期関数は多態性という用語に包括された。こうして元からの継承と合わせていわゆるオブジェクト指向の三大要素が確立された。同時に多重継承の問題も指摘され始め[[インタフェース (抽象型)|インターフェース]]という設計が取り上げられることになる。また、Smalltalkが標榜するメッセージ・メタファも単にオブジェクト指向の発案元であるという理由から一目置かれており、クラスのメソッドの呼び出しにこれを当てはめようとする考え方が一般化した。他方でSmalltalkの仕様に忠実であろうとする動きもあり、1984年に計算機科学者ブラッド・コックスが開発した「[[Objective-C]]」はSmalltalkをモデルにしてそれを平易化した言語であった。そのメッセージレシーバーはメソッドリストにないセレクタを受け取った場合のみに動的ディスパッチ機構に移るというスタイルで形式化された。程なくしてこのメッセージレシーバー実装の必要性には疑問符が付けられるようになったが、[[遠隔手続き呼出し]]のスタイルにはマッチしていたのでメッセージにある種の理想を抱く風潮はいつまでも残った。 |
|||
Simulaのクラス所属の手続きを通してクラス所属の変数を扱うという仕組みを、抽象データ構造と統合詳細化の叩き台にした[[エドガー・ダイクストラ|ダイクストラ]]に対して、[[パロアルト研究所]]の計算機科学者[[アラン・ケイ]]は「メッセージ」というプログラム概念のヒントにしている。またプログラム内のあらゆる要素をオブジェクトとして扱う考え方も編み出しており、オブジェクトはメッセージの送受信でコミュニケーションするとも提唱した。メッセージとはプログラムコードとしても解釈できるデータ列のことであり、そのデータ列を評価することで新たなデータを導出できるという仕組みを意味していた。オブジェクトが受け取ったデータ列は任意のタイミングで評価できるので非同期通信や遅延参照をも可能にした。ケイは[[LISP]]の影響も言及している。これらの構想に基づいてプログラム言語と専用開発環境を併せた「[[Smalltalk]]」が1972年に[[Alto|ゼロックスAlto]]上で初稼働された。Smalltalkの設計を説明するためにケイが考案した「[[オブジェクト指向]]」という用語はここで初めて発信された。またメッセージの構想は[[MIT]]の計算機科学者[[カール・ヒューイット]]に能動的な[[プロセス代数]]を意識させて、1973年発表の[[アクターモデル]]のヒントにもなった。しかしデータ列を常時コード候補として扱い続ける処理系は当時のコンピュータには負荷が大きく実用的な速度を得られないという問題にすぐ直面した。言語仕様改訂の過程で、やむなくメッセージはセレクタ仕様と共に本来期待された評価ができないまでに簡約され、レシーバーは動的ディスパッチとメソッド仕様が中心になり、オブジェクトもクラスの定義が中心になった。1980年の[[Smalltalk|Smalltalk-80]]は、元々メッセージの方を重視していたケイ自身が自嘲するまでに同期的で単純参照的で手続き的なオブジェクト指向へと変化していた。1981年に[[バイト (雑誌)|バイトマガジン]]がSmalltalkとケイが提唱するオブジェクト指向を紹介し、これが世間の注目を集める契機になったが、半ば形骸化していたメッセージ機構よりもクラス機構の方を重視させることにも繋がっている。以降、オブジェクト指向の定義は曖昧化して様々な解釈をもたらすようになった。 |
|||
'''C++の開発(1979~1985年)''' |
|||
一方、Smalltalkとは別にSimulaの影響を受け作られた[[C++]]([[1979年]])は[[抽象データ型]]のスーパーセットとしてのクラス、オブジェクトに注目し、オブジェクト指向をカプセル化、継承、多相性をサポートするものと再定義した(その際、実行時速度重視およびコンパイラ設計上の制約により、変数メタファである[[動的束縛]]の特徴は除外された)。これらは当初[[抽象データ型]]、[[派生]]、[[メソッド (計算機科学)#仮想関数|仮想関数]]と呼ばれ、オブジェクトのメンバ関数を実体ではなくポインタとすることで、継承関係にあるクラスのメンバ関数の[[オーバーライド]](上書き)を可能にしたことで、多相性を実現した(この流儀では'''メッセージメタファ'''はオブジェクト指向に必須ではないものと定義し、オブジェクトの持つ手続きをメソッドとは呼ばず[[メソッド (計算機科学)|メンバ関数]]と呼ぶ)。この他、Smalltalkにある[[動的束縛]]の類似的な機能としてオーバーロード([[多重定義]])が実装されている。 |
|||
C++の創始者[[ビャーネ・ストロヴストルップ]]は、Smalltalkが目指したある種の理想の追求には興味が無く、現用としての実用性を重視した。そのため、C++の再定義した「オブジェクト指向」は既存言語の拡張としてオブジェクト指向機能を実装できることでブレイクスルーを迎え急速に普及する。Smalltalkが単なるメソッドの動的呼び出しをメッセージ送信に見立て、呼び出すメソッドが見つからないときのみメッセージをハンドリングできるようにした「省コスト版」の機構を発明し以降それを採用するに至った経緯も手伝って、'''メッセージ送信'''という考え方はやや軽視されるようになり、オブジェクト指向とはC++の再定義したものと広く認知されるようになった。 |
|||
'''オブジェクト指向の普及(1985年~)''' |
|||
[[1980年]]代後半に次々と生まれたオブジェクト指向分析・設計論は、[[Smalltalk]]を源流とするオブジェクト指向を基に組み立てられた。そのころSmalltalkは商用展開こそされていたが広く普及しているとは言えず、一般には[[C++]]での[[実装]]が多くを占めた。しかしC++はSmalltalkと思想的にかなり異なる点や、同様のことを実現する際の実装面での複雑さや制約が問題とされた。このニーズを受けC++の提示した抽象データ型にクラスを適用する現実的な考え方と親しまれたALGOL系の構文を踏襲しつつ、内部的には柔軟なSmalltalkのオブジェクトモデルを採用し、'''メソッド'''などの一部用語やリフレクション、実行時動的性などSmalltalk色も取り入れた[[Java]]が注目を集めた([[1995年]]に登場。元々はモバイル機器向け言語処理系として開発された)。程なくSmalltalkやSELFで達成された[[仮想機械|仮想マシン(バイトコードインタープリタ)]]高速化技術の転用により実用的速度を得、バランス感覚に長けたJavaの台頭によって[[オブジェクト指向開発]]に必要な要素の多くが満たされ、[[1990年代]]後半からオブジェクト指向は広く普及するようになった。 |
|||
=== プロトタイプベースの考案(1985~90) === |
|||
[[Smalltalk]]のオブジェクト指向は、[[アラン・ケイ]]がその影響を言及していた[[LISP]]コミュニティを逆に感化して、Smalltalkが改めて提示したメタオブジェクトの概念を通したオブジェクト指向とLISP風プログラミングの連携に向けた構想が練られるようになった。LISPにはアトムとシンボル型というキーファクターが存在していたので、それと同様にオブジェクトのメンバ変数名とメンバ関数名自体をその都度評価(''eval'')して実行時の内容を導出し、実際の変数参照や関数呼出につなげるというアイディアが生まれた。これは実装面では単に、フレームと呼ばれる動的配列のスロットに変数や関数のポインタを付け替えするという機構にまとめられた。識別子(変数名と関数名)がマッピングされたスロットも増設削減可能であり、原型クラスと継承クラスのポインタも加えられた。このメタオブジェクト設計を導入して1985年に[[MIT人工知能研究所]]の[[LISPマシン]]上で「Flavors」が実装された。LISPの視点から保有スロット識別子の構成による[[動的型付け]]が盛り込まれ、それと多重継承を合わせた[[ミックスイン]]という設計が考案され、更にそれを平易化した[[ダックタイピング]]の概念も自然発生した。1988年にFlavorsのデザインを[[Common Lisp]]に融合させた「[[CLOS]]」が公開されたが、こちらは関数を中心にした一風変わったスタイルになった。Flavorsのデザインは[[パロアルト研究所]]にも回帰され、計算機科学者デビッド・アンガーがSmalltalkの方言として制作する「[[Self]]」を1987年に初回リリースした。LISPコミュニティから逆輸入されてSelfに導入されたメタオブジェクト設計は、後に[[プロトタイプベース]]またはインスタンスベースと呼ばれるパラダイムに発展し、[[Webプログラミング|WEBプログラム]]時代を迎えて大幅にプログラマ人口を増やしたオブジェクト指向[[スクリプト言語]]に大きな影響を与える事になった。同時にそれと、従来の[[クラス (コンピュータ)|クラス]]の仕組みを用いるオブジェクト指向言語を区別するための[[クラスベース]]という言葉も生まれた。 |
|||
== 代表的なオブジェクト指向言語 == |
== 代表的なオブジェクト指向言語 == |
||
オブジェクト指向言語は、[[抽象データ型]] |
オブジェクト指向言語は、[[抽象データ型]]の仕組みに沿った[[クラスベース]]、フレームとスロットの仕組みに沿った[[プロトタイプベース]]、[[Smalltalk]]をルーツにした[[メッセージパッシング|メッセージ]]構文ベースの三タイプに分類されるのが一般的である。[[クラスベース]]では「C++」「Java」「C#」が代表的である。[[プロトタイプベース]]では「Python」「JavaScript」「Ruby」が有名である。[[メッセージパッシング|メッセージ]]構文ベースでは「Smalltalk」「Objective-C」「Self」などがある。言語仕様の中でオブジェクト指向の存在感が比較的高い代表的なプログラミング言語は以下の通りである。 |
||
[[ファイル:History of object-oriented programming languages.svg|境界|中央|フレームなし]] |
[[ファイル:History of object-oriented programming languages.svg|境界|中央|フレームなし]] |
||
;[[Simula|Simula 67]] 1967年 |
;[[Simula|Simula 67]] 1967年 |
||
:1962年に公開された[[Simula]]の後継版であり、[[クラス (コンピュータ)|クラス]]のプログラム概念を導入した最初の言語である。 |
:1962年に公開された[[Simula]]の後継版であり、[[クラス (コンピュータ)|クラス]]のプログラム概念を導入した最初の言語である。物理モデルを解析するシミュレーション制作用に開発されたもので、クラスをメモリに展開したオブジェクトはその観測対象要素になった。Simulaのクラスは、一つのローカル変数構造と複数のプロシージャをまとめたミニモジュールと言えるものであったが、継承と仮想関数という先進的な設計を備えていた事でオブジェクト指向言語の草分けと見なされるようになった。[[クラスベース]]の源流である。 |
||
;[[Smalltalk]] 1972年 |
;[[Smalltalk]] 1972年 |
||
:[[メッセージパッシング]]のプログラム概念を導入した最初の言語。数値、真偽値、文字列から変数、コードブロック、メタデータまでのあらゆる要素をオブジェクトとするアイディアを編み出した最初の言語でもある。オブジェクト指向という言葉はSmalltalkの言語設計を説明する中で生み出された。オブジェクトにメッセージを送るという書式であらゆるプロセスを表現することが目標にされている。[[メッセージ転送|メッセージレシーバー]]と[[委譲]]の仕組みは、形式化されてない動的ディスパッチと[[ダイナミックバインディング|動的バインディング]]相当のものであり[[プロトタイプベース]]の源流になった。専用のランタイム環境上で動作させる設計 |
:[[メッセージパッシング]]のプログラム概念を導入した最初の言語。数値、真偽値、文字列から変数、コードブロック、メタデータまでのあらゆる要素をオブジェクトとするアイディアを編み出した最初の言語でもある。オブジェクト指向という言葉はSmalltalkの言語設計を説明する中で生み出された。オブジェクトにメッセージを送るという書式であらゆるプロセスを表現することが目標にされている。[[メッセージ転送|メッセージレシーバー]]と[[委譲]]の仕組みは、形式化されてない動的ディスパッチと[[ダイナミックバインディング|動的バインディング]]相当のものであり[[プロトタイプベース]]の源流にもなった。専用のランタイム環境上で動作させる設計も模範にされ、これは後に[[仮想マシン]]や[[仮想実行システム]]と呼ばれるものになる。 |
||
;[[C++]] 1983年 |
;[[C++]] 1983年 |
||
:[[C言語]]に[[クラスベース]]のオブジェクト指向を追加したもの。Simulaの影響を受けている。[[静的型付け]]の[[クラス (コンピュータ)|クラス]]が備えられて、カプセル化、継承、多態性の三仕様を実装している。カプセル化はフレンド指定で |
:[[C言語]]に[[クラスベース]]のオブジェクト指向を追加したもの。Simulaの影響を受けている。[[静的型付け]]の[[クラス (コンピュータ)|クラス]]が備えられて、カプセル化、継承、多態性の三仕様を実装している。カプセル化はアクセス修飾子とフレンド指定子の双方を定義できる。継承は多重継承、オーバーライド制約用の継承可視性、[[菱形継承問題]]解決用の[[仮想継承]]も導入されている。多態性は[[仮想関数]]によるサブタイプ多相、[[テンプレート (プログラミング)|テンプレートクラス&関数]]によるパラメトリック多相、[[多重定義|関数&演算子オーバーロード]]によるアドホック多相が導入されている。元がC言語であるため、オブジェクト指向から逸脱したコーディングも多用できる点が物議を醸したが、その是非はプログラマ次第であるという結論に落ち着いた。 |
||
;[[Objective-C]] 1984年 |
;[[Objective-C]] 1984年 |
||
:[[C言語]]に[[メッセージパッシング|メッセージ]]構文ベースのオブジェクト指向を追加したもの。こちらはSmalltalkの影響を受けており、それに準じた[[メッセージパッシング]]の書式が備えられた。メッセージを受け取るクラスの定義による[[静的型付け]]と共に、メッセージを[[委譲]]するオブジェクトの実行時決定による[[動的型付け]]も設けられている。オブジェクト指向的にはC++よりも正統と見なされた。[[制御構造|制御構造文]]が追加され、メッセージを送る書式も平易化されており、Smalltalkよりも扱いやすくなった。 |
:[[C言語]]に[[メッセージパッシング|メッセージ]]構文ベースのオブジェクト指向を追加したもの。こちらはSmalltalkの影響を受けており、それに準じた[[メッセージパッシング]]の書式が備えられた。メッセージを受け取るクラスの定義による[[静的型付け]]と共に、メッセージを[[委譲]]するオブジェクトの実行時決定による[[動的型付け]]も設けられている。オブジェクト指向的にはC++よりも正統と見なされた。[[制御構造|制御構造文]]が追加され、メッセージを送る書式も平易化されており、Smalltalkよりも扱いやすくなった。 |
||
;[[Object Pascal]] 1986年 |
;[[Object Pascal]] 1986年 |
||
:[[Pascal]]にクラスベースのオブジェクト指向を追加したもの。 |
:[[Pascal]]にクラスベースのオブジェクト指向を追加したもの。当初はモジュールのデータ隠蔽的なカプセル化、単一継承、仮想関数による多態性という基本的なものだった。静的型付け重視である。[[多重定義|関数&演算子オーバーロード]](アドホック多相)と[[ジェネリックプログラミング|ジェネリクス]](パラメトリック多相)は当初採用に到らなかった。[[ニクラウス・ヴィルト|ヴィルト]]監修の[[アップル (企業)|アップル社]]による初回バージョンを基礎にして様々な企業団体による派生版が公開されており、その特徴と機能追加も様々である。 |
||
;[[Eiffel]] 1986年 |
;[[Eiffel]] 1986年 |
||
:[[C++]]の柔軟性と融通性とは正反対のオブジェクト指向言語。[[クラスベース]]で[[静的型付け]]重視である。[[契約プログラミング]]を理念にしており、アサーションの挿入でクラスの状態とメソッド引数&返り値を細かくチェックできる。クラスメンバ(フィーチャー)は属性、アクセッサ、ミューテイタの三種限定で[[多重定義|オーバーロード]]はできない。カプセル化の可視性は自身に依存するクラス(クライアント)を定義するという形で決められる。多重継承可能であり、クラス間の繋がりを[[仮想継承]]機能、各種[[オーバーライド]]指定子、名前衝突を解決するリネーミング機能などで綿密に設定できる。仮想関数 |
:[[C++]]の柔軟性と融通性とは正反対のオブジェクト指向言語。[[クラスベース]]で[[静的型付け]]重視である。[[契約プログラミング]]を理念にしており、アサーションの挿入でクラスの状態とメソッド引数&返り値を細かくチェックできる。クラスメンバ(フィーチャー)は属性、アクセッサ、ミューテイタの三種限定で[[多重定義|オーバーロード]]はできない。カプセル化の可視性は自身に依存するクラス(クライアント)を定義するという形で決められる。多重継承可能であり、クラス間の繋がりを[[仮想継承]]機能、各種[[オーバーライド]]指定子、名前衝突を解決するリネーミング機能などで綿密に設定できる。延期関数(仮想関数)と[[テンプレート (プログラミング)|テンプレート]]相当の[[ジェネリックプログラミング|ジェネリッククラス]]も導入されている。[[ガーベジコレクション]]機能が初めて導入されたオブジェクト指向言語でもある。 |
||
;[[Self]] 1987年 |
;[[Self]] 1987年 |
||
:[[メッセージパッシング|メッセージ]]構文ベースのオブジェクト指向言語。標準配備のオブジェクトを複製して、そのスロットに任意のプロパティとメソッドを[[ダイナミックバインディング|動的バインディング]]できるという[[プロトタイプベース]]を初めて導入したオブジェクト指向言語でもある。ゆえに[[動的型付け]]重視である。Smalltalkと同様に専用のランタイム環境で実行され |
:[[メッセージパッシング|メッセージ]]構文ベースのオブジェクト指向言語。標準配備のオブジェクトを複製して、そのスロットに任意のプロパティとメソッドを[[ダイナミックバインディング|動的バインディング]]できるという[[プロトタイプベース]]を初めて導入したオブジェクト指向言語でもある。ゆえに[[動的型付け]]重視である。当初はSmalltalkの派生言語として公開されており、それと同様に専用のランタイム環境上で実行され、GUI運用環境の構築も目標にしていた。Selfのランタイム環境は[[実行時コンパイラ]]機能を初めて実装したことで知られており画期的な処理速度を実現している。この技術は[[Java仮想マシン]]の土台になった。 |
||
;[[CLOS]] 1988年 |
;[[CLOS]] 1988年 |
||
:[[Common Lisp]]に[[プロトタイプベース]]に似たオブジェクト指向を追加したもの。 |
:[[Common Lisp]]に[[プロトタイプベース]]に似たオブジェクト指向を追加したもの。[[構造体]]オブジェクトと[[多重定義|多重定義関数]]オブジェクトに分離されており、前者のスロットには任意のフィールドを、後者のスロットには任意のパラメータパターンを[[ダイナミックバインディング|動的バインディング]]できる動的型付け重視である。動的型付けの構造体オブジェクトを引数として渡される関数の[[多重ディスパッチ]]が重視されている。 |
||
;[[Python]] 1994年 |
;[[Python]] 1994年 |
||
:[[プロトタイプベース]]と[[クラスベース]]の双方を兼ねたオブジェクト指向スクリプト言語。静的型付けのクラスと動的型付けのインスタンスが併用されているが、後者の動的バインディングの比重が大きめである。[[ダックタイピング]]を重視する方針により型宣言制約が撤廃されている。多態性は動的ディスパッチを中心にし、メソッドシグネチャと[[関数プロトタイプ]]を操作できる[[リフレクション (情報工学)|リフレクション]]によって更に柔軟性が図られている。これらにより動的型付け重視である。ジェネリッククラスとジェネリック関数も導入されており、動的な柔軟性と静的な多様性の双方を使い分けられる。構文と書式を比較的簡素化し、[[インタプリタ]]式動作なので堅牢性も高い。 |
:[[プロトタイプベース]]と[[クラスベース]]の双方を兼ねたオブジェクト指向スクリプト言語。静的型付けのクラスと動的型付けのインスタンスが併用されているが、後者の動的バインディングの比重が大きめである。[[ダックタイピング]]を重視する方針により型宣言制約が撤廃されている。多態性は動的ディスパッチを中心にし、メソッドシグネチャと[[関数プロトタイプ]]を操作できる[[リフレクション (情報工学)|リフレクション]]によって更に柔軟性が図られている。これらにより動的型付け重視である。ジェネリッククラスとジェネリック関数も導入されており、動的な柔軟性と静的な多様性の双方を使い分けられる。構文と書式を比較的簡素化し、[[インタプリタ]]式動作なので堅牢性も高い。 |
||
;[[Java]] 1995年 |
;[[Java]] 1995年 |
||
:[[C++]]をモデルにしつつ堅牢性とセキュリティを重視した[[クラスベース]]のオブジェクト指向言語。静的型付け重視である。パッケージ中心のカプセル化、単一のみの継承、仮想関数と多重実装可な[[インタフェース (抽象型)|インターフェース]]による多態性と、基本に忠実なクラスベースである。[[多重定義|メソッドオーバーロード]]と、クラスメタデータを操作できる[[リフレクション (情報工学)|リフレクション]]は初期から採用された。データコンテナ系のクラスと関数型インターフェースなどに限ってジェネリ |
:[[C++]]をモデルにしつつ堅牢性とセキュリティを重視した[[クラスベース]]のオブジェクト指向言語。静的型付け重視である。パッケージ中心のカプセル化、単一のみの継承、仮想関数と多重実装可な[[インタフェース (抽象型)|インターフェース]]による多態性と、基本に忠実なクラスベースである。[[多重定義|メソッドオーバーロード]]と、クラスメタデータを操作できる[[リフレクション (情報工学)|リフレクション]]は初期から採用された。データコンテナ系のクラスと関数型インターフェースなどに限って[[ジェネリクス]]が導入されている。C++の[[ポインタ (プログラミング)|ポインタ]]と値型インスタンスと[[演算子オーバーロード]]は真っ先に除外され、[[例外処理]]は残された。[[仮想マシン]]上で実行される。[[仮想マシン]]と[[ガーベジコレクション]]の技術は比較的高度と見なされている。 |
||
;[[Delphi]] 1995年 |
;[[Delphi]] 1995年 |
||
:[[Object Pascal]]を発展させたもの。それと同様にこちらも基本に忠実なクラスベースで静的型付け重視であった。当初はデータベース操作プログラム開発を主な用途にして公開された。クラスとレコード([[構造体]])に同等の比重が置かれていた。一時期Javaの対抗馬になった。 |
:[[Object Pascal]]を発展させたもの。それと同様にこちらも基本に忠実なクラスベースで静的型付け重視であった。当初はデータベース操作プログラム開発を主な用途にして公開された。クラスとレコード([[構造体]])に同等の比重が置かれていた。一時期Javaの対抗馬になった。 |
||
99行目: | 81行目: | ||
:[[Smalltalk]]の思想を受け継いでデザインされたオブジェクト指向スクリプト言語。当初は[[ウェブアプリケーション|WEBアプリケーション]]開発を主な用途にして公開された。[[プロトタイプベース]]であり、オブジェクトを純然たるスロットの集合体として定義している。スロットにはプロパティとメソッドが[[ダイナミックバインディング|動的バインディング]]され、[[ダックタイピング]]で型識別される。この仕組みによる[[動的な型付け|動的型付け]]が本命にされて、[[プリミティブ型]]以外の[[静的型付け]]が放棄されている。オブジェクトはプロトタイプのクローンであり、そのプロトタイプで分類される。プロトタイプの方は継承で体系化されている。[[ECMAScript]]として標準化されている。2015年版からは[[クラスベース]]向けの構文もサポートするようになった。 |
:[[Smalltalk]]の思想を受け継いでデザインされたオブジェクト指向スクリプト言語。当初は[[ウェブアプリケーション|WEBアプリケーション]]開発を主な用途にして公開された。[[プロトタイプベース]]であり、オブジェクトを純然たるスロットの集合体として定義している。スロットにはプロパティとメソッドが[[ダイナミックバインディング|動的バインディング]]され、[[ダックタイピング]]で型識別される。この仕組みによる[[動的な型付け|動的型付け]]が本命にされて、[[プリミティブ型]]以外の[[静的型付け]]が放棄されている。オブジェクトはプロトタイプのクローンであり、そのプロトタイプで分類される。プロトタイプの方は継承で体系化されている。[[ECMAScript]]として標準化されている。2015年版からは[[クラスベース]]向けの構文もサポートするようになった。 |
||
;[[C Sharp|C#]] 2000年 |
;[[C Sharp|C#]] 2000年 |
||
:[[Java]]を強く意識してマイクロソフト社が開発したクラスベースのオブジェクト指向言語。C++のクラスの性質を残しながらマルチパラダイムに発展させている。拡張メソッドや演算子オーバーロードなどのアドホック多相的なコーディングサポートが豊富である。パラメトリック多相は型変数の[[共変性と反変性 (計算機科学)|共変性と反変性]]、型引数 |
:[[Java]]を強く意識してマイクロソフト社が開発したクラスベースのオブジェクト指向言語。C++のクラスの性質を残しながらマルチパラダイムに発展させている。拡張メソッドや演算子オーバーロードなどのアドホック多相的なコーディングサポートが豊富である。パラメトリック多相の[[ジェネリクス]]は型変数の[[共変性と反変性 (計算機科学)|共変性と反変性]]、型引数の型制約を備えている。サブタイプ多相は、クラスは単一継承でインターフェースは多重実装と基本通りである。数々の[[関数型言語|関数型プログラミング]]機能も導入されている。基本は[[静的型付け]]であるが、動的束縛型(dynamic型)と[[ダックタイピング]]による[[動的型付け]]の存在感が高められているので、漸進的型付けの言語と見なされている。[[.NET Framework]]([[共通言語基盤]]=仮想実行システム)上で実行される。 |
||
;[[Scala]] 2003年 |
;[[Scala]] 2003年 |
||
:[[クラスベース]]のオブジェクト指向と[[関数型プログラミング]]を融合させた言語。[[ |
:[[クラスベース]]のオブジェクト指向と[[関数型プログラミング]]を融合させた言語。[[クラス (コンピュータ)|クラス]]機構と関数型の[[型システム]]に同等の比重が置かれており静的型付け重視である。[[ミックスイン]]相当の[[トレイト]]と[[ジェネリクス]]を連携させた多態性が重視されている。型変数の[[共変性と反変性 (計算機科学)|バリアンス]]、[[共変性と反変性 (計算機科学)|共変と反変]]双方の型境界、抽象型メンバ、[[オーバーライド]]、ジェネリックトレイト、抽象クラスの組み合わせで[[派生型|派生型付け]]されたオブジェクトは様々に体系化される。また、[[イミュータブル]]なオブジェクト(caseクラス)、オブジェクトの[[非交和]]構造(sealedクラス)、オブジェクト引数の[[逆写像|抽出]](unapplyメソッド)とオブジェクトの[[パターンマッチング|パターンマッチング式]]の組み合わせは、[[抽象データ型]]を値として扱う独特の関数型スタイルを表現できる。 |
||
;[[Kotlin]] 2011年 |
;[[Kotlin]] 2011年 |
||
:[[Javaバイトコード]]を出力し、[[Java仮想マシン]]上で動作するJavaテクノロジ互換言語である。グローバル関数、グローバル変数の使用も容認されており、オブジェクト指向プログラミングを手続き型プログラミングのスタイルに崩したかのようにデザインされている。静的型付け重視である。 |
:[[Javaバイトコード]]を出力し、[[Java仮想マシン]]上で動作するJavaテクノロジ互換言語である。グローバル関数、グローバル変数の使用も容認されており、オブジェクト指向プログラミングを手続き型プログラミングのスタイルに崩したかのようにデザインされている。静的型付け重視である。 |
||
;[[TypeScript]] 2012年 |
;[[TypeScript]] 2012年 |
||
:[[JavaScript]]を強く意識してマイクロソフト社が開発したオブジェクト指向スクリプト言語。JavaScriptのプログラムを静的型付けで補完した言語である。[[クラスベース]]向けの構文と、[[関数型プログラミング]]の[[型システム]]のスタイルが加えられている。特に後者の性質が強調されている事から静的型付け重視である。継承構造によるサブタイプ多相はほぼ除外されており、パラメトリック多相とアドホック多相で |
:[[JavaScript]]を強く意識してマイクロソフト社が開発したオブジェクト指向スクリプト言語。JavaScriptのプログラムを静的型付けで補完した言語である。[[クラスベース]]向けの構文と、[[関数型プログラミング]]の[[型システム]]のスタイルが加えられている。特に後者の性質が強調されている事から静的型付け重視である。継承構造によるサブタイプ多相はほぼ除外されており、パラメトリック多相とアドホック多相でオブジェクトを扱うという[[ジェネリクス]]と型アノテーション重視の言語設計になっている。オブジェクト指向ではあるが関数型の性格が強めである。 |
||
;[[Swift (プログラミング言語)|Swift]] 2014年 |
;[[Swift (プログラミング言語)|Swift]] 2014年 |
||
:[[Objective-C]]を発展させたものであるが、メッセージ構文は破棄されており、クラスベースのオブジェクト指向になっている。オブジェクトの[[イミュータブル|イミュータブル性]]が重視されている。単一継承が採用されているが可視性にプロテクト指定が無いので縦並びの継承は軽視されており、プロトコルの横並びの多重実装を重視している。プロトコルは[[インタフェース (抽象型)|インターフェース]]と[[ミックスイン]]の中間的機能であり、双方の短所を解決する様々な仕組みが導入されている。インスタンスはプロトコルを基準にして型分類され、また抽象化される。プロトコルと[[ジェネリクス]]の連携による動的束縛型(Opaque型)の存在感が高められており、それと[[静的型付け]]のクラスを併用する漸進的型付けの言語と言える。 |
:[[Objective-C]]を発展させたものであるが、メッセージ構文は破棄されており、クラスベースのオブジェクト指向になっている。オブジェクトの[[イミュータブル|イミュータブル性]]が重視されている。単一継承が採用されているが可視性にプロテクト指定が無いので縦並びの継承は軽視されており、プロトコルの横並びの多重実装を重視している。プロトコルは[[インタフェース (抽象型)|インターフェース]]と[[ミックスイン]]の中間的機能であり、双方の短所を解決する様々な仕組みが導入されている。インスタンスはプロトコルを基準にして型分類され、また抽象化される。プロトコルと[[ジェネリクス]]の連携による動的束縛型(Opaque型)の存在感が高められており、それと[[静的型付け]]のクラスを併用する漸進的型付けの言語と言える。 |
||
== 用語と解説 == |
== 用語と解説 == |
||
;[[クラス (コンピュータ)|クラス]] |
|||
{{Wikify|section=1|date=2020年8月}} <!-- 見出し中のリンク除去 |
|||
:クラス(''class'')の仕組みを中心にしたオブジェクト指向を[[クラスベース]]と言う。クラスはデータメンバとメソッドをまとめたものであり、[[プログラム意味論|セマンティクス]]を付加された静的[[構造体|レコード]]とも解釈される。ここでのセマンティクスとはデータの用法を表わすメソッドを指す。クラスはインスタンスのひな型になる。クラスはカプセル化、継承、多態性の三機能を備えていることが求められている。カプセル化はデータメンバとメソッドの可視性を指定する機能である。継承は自身のスーパークラスを指定する機能である。多態性はオーバーライドと[[仮想関数テーブル]]を処理する機能である。コンストラクタとデストラクタの実装も必要とされている。前者はインスタンス生成時に、後者はインスタンス破棄時に呼び出されるメソッドである。 |
|||
https://ja-two.iwiki.icu/wiki/WP:MSH#NOLINK |
|||
--> |
|||
;プロトタイプオブジェクト |
|||
:プロトタイプ(''prototype'')の仕組みを中心にしたオブジェクト指向を[[プロトタイプベース]]と言う。プロトタイプベースで言われるオブジェクトとは、中間参照ポインタの動的配列を指す。この動的配列は一般にフレームと呼ばれる。中間参照ポインタは一般にスロットと呼ばれる。スロットにはデータメンバとメソッドの参照が代入されるので、オブジェクトはクラスと同様にデータメンバとメソッドをまとめたものになる。オブジェクトはプロトタイプオブジェクトとオブジェクトに分かれる。前者はクラス、後者はインスタンスに当たるものである。前者はシステム提供プロトタイプとユーザー定義プロトタイプに分かれる。プログラマはシステム提供プロトタイプを派生させてユーザー定義プロトタイプを作成する。プロトタイプには、規定の設計に基づいたデータメンバ参照とメソッド参照が代入されており、オブジェクトのひな型になる。プロトタイプは親プロトタイプ参照用スロットを保持しており、これは継承と類似の機能になる。プロトタイプを複製する形式でオブジェクトは生成される。オブジェクトは複製元プロトタイプと同じデータメンバとメソッドを保持しているが、生成後は任意のデータメンバとメソッドを自由に付け替えできる。オブジェクトは複製元プロトタイプ参照用スロットを保持している。複製元プロトタイプからその親プロトタイプを辿れる参照のリンクによってオブジェクトは一定の体系化がなされている。 |
|||
;[[メッセージ (コンピュータ)|メッセージ]] |
|||
:オブジェクト指向で言われるメッセージ(''message'')は、複数の方面の考え方が混同されている曖昧な用語になっている。元々はSmalltalkから始まったメッセージ構文ベースのオブジェクト指向の中心機構である。以前はクラスベースの方でもメソッドの呼び出しをメッセージを送るという風に考えることが推奨されていた。メッセージはオブジェクトのコミュニケーション手段と標榜されているが、その忠実な実装内容はそれほど知られていないのが実情である。最も混同されているものに[[アクターモデル]]があるが、そこで言われる非同期性とオブジェクト指向で言われる評価の遅延性は現行の実装スタイルではそれほど共通していない。コンポーネント準拠ソフトウェア工学と[[Object Request Broker|オブジェクトリクエストブローカー]]で言われる[[ソフトウェアコンポーネント]]同士の通信もメッセージパッシングと呼ばれることが多いが、その仕様と機能は動的ディスパッチに該当するものである。メッセージのオブジェクト指向的運用はメッセージングと名付けられている。具体的な機能例としてはSmalltalk、Objective-C、Selfの[[メッセージ転送|メッセージレシーバー]]と、Rubyのメソッドミッシングなどがあるが、いずれもメッセージングの本質ではないとも言われている。 |
|||
;[[インスタンス]] |
|||
:(''instance'')はクラスベースではクラスを実体化したものであり、実装レベルで言うとデータメンバと仮想関数テーブルをメモリ上に展開したものになる。プロトタイプベースではプロトタイプオブジェクトのクローンで生成されたオブジェクトを指す。実装レベルで言うとメモリ上に展開された中間参照ポインタの動的配列になる。 |
|||
;[[フィールド (計算機科学)|データメンバ]] |
|||
:(''data member'')はクラスまたはオブジェクトに属する変数。言語によってフィールド、プロパティ、メンバ変数、属性と呼ばれる。データメンバは、クラスデータメンバとインスタンスデータメンバに分かれる。クラスデータメンバは静的データメンバとも呼ばれる。その中で定数化されたものはクラス[[定数 (プログラミング)|定数]]と呼ばれる。クラスデータメンバはクラス名の名前空間でスコープされたグローバル変数と同じものであり、プログラム開始時から終了時まで確保される。インスタンスデータメンバはインスタンス生成時にメモリ上に確保されるものであり、その破棄時に消滅する。プロトタイプベースではプロトタイプオブジェクトが保持する特定のデータメンバが静的データメンバに該当するものになる。 |
|||
;[[メソッド (計算機科学)|メソッド]] |
|||
:(''method'')はクラスまたはオブジェクトに属する関数。言語によってはメンバ関数とも呼ばれる。データメンバの参照に特化したものはゲッター(''getter'')アクセッサ(''accessor'')と呼ばれる。データメンバの変更に特化したものはセッター(''setter'')ミューテイタ(''mutator'')と呼ばれる。メソッドは、クラスメソッドとインスタンスメソッドに分かれる。クラスメソッドは静的メソッドとも呼ばれる。クラスメソッドはクラス名の名前空間でスコープされたグローバル関数と同じものである。インスタンスメソッドを呼び出すには、そのメソッドが属するインスタンス参照が必要になる。これはthisインスタンスと呼ばれる。プロトタイプベースではプロトタイプオブジェクトが保持する特定のメソッドが静的メソッドに該当するものになる。 |
|||
;[[コンストラクタ]] |
|||
:(''constructor'')はインスタンス生成時に呼び出されるそのクラスのメソッドである。インスタンスデータメンバを任意の値で初期化するためのものであるが、その他の初期化コードも記述できる。プロトタイプベースではプロトタイプオブジェクトと同名のグローバル関数として存在している。 |
|||
;[[デストラクタ]] |
|||
:(''destructor'')はインスタンス破棄時に呼び出されるそのクラスのメソッドである。インスタンス破棄の影響を解決する任意の後始末コードを記述できる。インスタンスの破棄は占有メモリの解放を意味する。なお、ガーベジコレクタ実装言語ではファイナライザになっている事がある。プログラマが呼び出すデストラクタの方はその終了がメモリ解放に直結してるのに対し、ガーベジコレクタが呼び出すファイナライザの方はそうではない。 |
|||
;アクセスコントロール |
|||
:(''access control'')はカプセル化に基づくデータメンバとメソッドの可視性を決定するものである。これはスコープ基準とクライアント基準の二通りがある。スコープ基準の可視性はプライベート、プロテクト、パブリックの三種が基本である。プライベートは同クラス内のみ、プロテクトは同クラス内と派生クラス内のみ、パブリックはどこからでもアクセス可能である。クライアント基準の可視性は自クラス内のメンバへのアクセスを許可するクライアントクラスないしフレンドクラスを定義する方法で決められる。クライアントクラス指定はそのサブクラスを含むこともあり継承関係で一括定義できる。 |
|||
;[[インタフェース (抽象型)|インターフェース]] |
|||
:(''interface'')はプログラム概念と機能名の双方を指す用語である。言語によってはプロトコルと言われる。抽象メソッドと具象メソッド(実装内容付き)で構成される純粋抽象~半抽象クラスを意味する。クラスの振る舞い局面を抽出したものであり、[[統一モデリング言語|UML]]では実現と言われる。クラスによるインターフェースの継承は実装と呼ばれる。多重実装可が普通である。ミックスインとの違いは、抽象階層に焦点が当てられている事であり、直下の実装オブジェクトを共通の振る舞い局面でまとめることがその役割である。インターフェースは自身の実装オブジェクトをグループ化できる。{{仮リンク|記名的型付け|en|Nominal type system|label=}}に準拠しているのでインターフェースの実装の明記が振る舞い局面の識別基準になる。インターフェースは抽象メソッド主体なので多重継承時のメンバ名の重複はあまり問題にならない。共通の実装メソッドに集約されるからである。インターフェースは非インスタンス対象である。 |
|||
;[[ミックスイン]] |
|||
:(''mixin'')はインターフェースに似たプログラム概念を指す用語である。機能名は言語によって[[トレイト]]またはプロトコルと言われる。抽象&具象メソッドとデータメンバで構成される継承専用クラスを意味する。クラスを特徴付けるための装飾部品である。クラスによるトレイトの継承は実装と呼ばれる。多重実装可が普通である。インターフェースとの違いは、トレイトの実装階層に焦点が当てられている事であり、オブジェクトを所有メンバで特定してまとめることがその役割である。トレイトは自身の[[上位集合]]であるオブジェクトをグループ化できる。{{仮リンク|構造的型付け|en|Structural type system|label=}}に準拠しているので所属メンバ構成自体がトレイト等価性の識別基準になる。これはトレイト実装を明記してなくても、そのトレイトが内包する全メンバを所持していれば同じトレイトと見なされることを意味する。トレイトは合成や交差が可能である。トレイトは多重継承時のメンバ名重複の際にその参照の優先順位に注意する必要がある。トレイトは非インスタンス対象である。 |
|||
;[[ダックタイピング]] |
|||
=== クラス === |
|||
:''(duck typing'')は特定のデータメンバ名またはメソッド名(メソッドシグニチャ)を持っているかどうかでインスタンスを分類すること。または選り分けること。実行時に判別する仕組みであり、動的型付けに分類される。選り分けられたインスタンスはその指名データメンバないし指名メソッドでのアクセス対象になる。 |
|||
[[クラス (コンピュータ)|クラス]](''class'')の仕組みを中心にしたオブジェクト指向を[[クラスベース]]と言う。クラスはデータメンバとメソッドをまとめたものであり、[[プログラム意味論|セマンティクス]]を付加された静的[[構造体|レコード]]とも解釈される。ここでのセマンティクスとはデータの用法を表わすメソッドを指す。クラスはインスタンスのひな型になる。クラスはカプセル化、継承、多態性の三機能を備えていることが求められている。カプセル化はデータメンバとメソッドの可視性を指定する機能である。継承は自身のスーパークラスを指定する機能である。多態性はメソッドの抽象化と[[仮想関数テーブル]]を処理する機能である。コンストラクタとデストラクタの実装も必要とされている。前者はインスタンス生成時に、後者はインスタンス破棄時に呼び出されるメソッドである。 |
|||
;[[メタクラス]] |
|||
=== プロトタイプオブジェクト === |
|||
:(''metaclass'')とはクラスを定義しているクラスであるが、その実態はシステム側が用意している特別なシングルトンオブジェクトと考えた方が分かりやすい。システム内のクラス定義情報をクラスに見立てて、それをインスタンス化したものである。慣例的にこれをメタクラスと呼ぶ。メタクラスはクラスのデータメンバとメソッドの定義情報を指し、それを操作する機能はリフレクションと呼ばれる。クラスベースで用いられるものである。 |
|||
プロトタイプ(''prototype'')の仕組みを中心にしたオブジェクト指向を[[プロトタイプベース]]と言う。プロトタイプベースで言われるオブジェクトとは、中間参照ポインタの動的配列を指す。この動的配列は一般にフレームと呼ばれる。中間参照ポインタは一般にスロットと呼ばれる。スロットにはデータメンバとメソッドの参照が代入されるので、オブジェクトはクラスと同様にデータメンバとメソッドをまとめたものになる。オブジェクトはプロトタイプオブジェクトとオブジェクトに分かれる。前者はクラス、後者はインスタンスに当たるものである。前者はシステム提供プロトタイプとユーザー定義プロトタイプに分かれる。プログラマはシステム提供プロトタイプを派生させてユーザー定義プロトタイプを作成する。プロトタイプには、規定の設計に基づいたデータメンバ参照とメソッド参照が代入されており、オブジェクトのひな型になる。プロトタイプは親プロトタイプ参照用スロットを保持しており、これは継承と類似の機能になる。プロトタイプを複製する形式でオブジェクトは生成される。オブジェクトは複製元プロトタイプと同じデータメンバとメソッドを保持しているが、生成後は任意のデータメンバとメソッドを自由に付け替えできる。オブジェクトは複製元プロトタイプ参照用スロットを保持している。複製元プロトタイプからその親プロトタイプを辿れる参照のリンクによってオブジェクトは一定の体系化がなされている。 |
|||
;[[リフレクション (情報工学)|リフレクション]] |
|||
=== メッセージ === |
|||
:(''reflection'')はクラスの定義情報を変更する機能であるが、言語ごとに変更できる定義情報の範囲は異なっている。データメンバではデータ型、識別子、可視性が変更対象になる。メソッドではリターン型、識別子、パラメータリスト、可視性、仮想指定が変更対象になる。双方の追加定義と削除もできる事がある。スーパークラスも変更できる事がある。また、実行時の文字列(char配列やString)をデータメンバとメソッドの内部識別子として解釈できる機能もリフレクションに当たる。これは実行時の文字列によるデータメンバの参照とメソッドの呼び出しを可能にする。 |
|||
オブジェクト指向で言われる[[メッセージ (コンピュータ)|メッセージ]](''message'')は、複数の方面の考え方が混同されている曖昧な用語になっている。元々はSmalltalkから始まったメッセージ構文ベースのオブジェクト指向の中心機構である。以前はクラスベースの方でもメソッドの呼び出しをメッセージを送るという風に考えることが推奨されていた。メッセージはオブジェクトのコミュニケーション手段と標榜されているが、その忠実な実装内容はそれほど知られていないのが実情である。最も混同されているものに[[アクターモデル]]があるが、そこで言われる非同期性とオブジェクト指向で言われる評価の遅延性は現行の実装スタイルではそれほど共通していない。コンポーネント準拠ソフトウェア工学と[[Object Request Broker|オブジェクトリクエストブローカー]]で言われる[[ソフトウェアコンポーネント]]同士の通信もメッセージパッシングと呼ばれることが多いが、その仕様と機能は動的ディスパッチに該当するものである。メッセージのオブジェクト指向的運用はメッセージングと名付けられている。具体的な機能例としてはSmalltalk、Objective-C、Selfの[[メッセージ転送|メッセージレシーバー]]と、Rubyのメソッドミッシングなどであるが、いずれもメッセージングのサブセットである。 |
|||
;遅延バインディング |
|||
:(''late binding'')は、識別子が参照するオブジェクトをコンパイル時に決める事前バインディング(''early binding'')の対義語であり、この場合は識別子の参照先を実行時に決める動的バインディングとほぼ同じ意味で用いられる。一方で、特にリフレクション機能を通して実装される方を遅延バインディングとする考え方もある。抽象化された型に対して、実行時の文字列(char配列やString)を内部識別子に解釈し、コンパイル時には認識されていなかったオブジェクトをローディングして代入する仕組みなどである。オブジェクトの呼び出しが、[[ダイナミックリンクライブラリ|DLL]]やクラスライブラリの動的ローディングに繋がることが遅延バインディングと呼ばれる基準になる。また、プログラム内でデータとして扱われている[[コードブロック]]を関数の型に代入して呼び出すという仕組みがある。そのコードブロックは文字値と数値の混合配列であり、リフレクション機能を利用して実行する。 |
|||
(''instance'')はクラスベースではクラスを実体化したものであり、実装レベルで言うとデータメンバと仮想関数テーブルをメモリ上に展開したものになる。プロトタイプベースではプロトタイプオブジェクトのクローンで生成されたオブジェクトを指す。実装レベルで言うとメモリ上に展開された中間参照ポインタの動的配列になる。 |
|||
;動的ディスパッチ |
|||
=== [[フィールド (計算機科学)|データメンバ]] === |
|||
:(''dynamic dispatch'')はメソッドの呼び出しを受けるオブジェクトの側に焦点を当てたプログラム概念である。一般的なローカルメソッドでは、メソッド識別子にマッピングされている参照が指すメソッド実体を呼び出す仕組みを意味する。参照が指す先はプログラム実行中に随時変更されるのでコンパイル時ではなく実行時のその都度に確定されることになる。リモートメソッドでは、受け取ったバイトデータ列を解釈しリフレクション機能でメソッドを呼び出す仕組みを意味する。受信側の実行時状態による選択が加えられる事もある。始めのアクセスで所有メソッドリストを呼び出し側に送り、無駄なエラーリクエストを無くす仕組みと併用される事が多い。 |
|||
(''data member'')はクラスまたはオブジェクトに属する変数。言語によってフィールド、プロパティ、メンバ変数、属性と呼ばれる。データメンバは、クラスデータメンバとインスタンスデータメンバに分かれる。クラスデータメンバは静的データメンバとも呼ばれる。その中で定数化されたものはクラス[[定数 (プログラミング)|定数]]と呼ばれる。クラスデータメンバはクラス名の名前空間でスコープされたグローバル変数と同じものであり、プログラム開始時から終了時まで確保される。インスタンスデータメンバはインスタンス生成時にメモリ上に確保されるものであり、その破棄時に消滅する。プロトタイプベースではプロトタイプオブジェクトが保持する特定のデータメンバが静的データメンバに該当するものになる。 |
|||
;[[動的束縛|動的バインディング]] |
|||
=== [[メソッド (計算機科学)|メソッド]] === |
|||
:(''dynamic binding'')は特定の識別子から呼び出されるメソッドないし参照されるデータメンバが、コンパイル時ではなく実行時に決められる仕組み全般を指す用語である。プロトタイプベースのオブジェクトからメソッドとデータメンバが参照される機構、仮想関数メソッドから派生クラスのメソッドが呼び出されるシングルディスパッチ機構、メソッドに渡された実引数を実行時型チェックしてその結果に従いプロセスを分岐させるシングルディスパッチ~多重ディスパッチ機構などが例である。 |
|||
(''method'')はクラスまたはオブジェクトに属する関数。言語によってはメンバ関数とも呼ばれる。データメンバの参照に特化したものはゲッター(''getter'')アクセッサ(''accessor'')と呼ばれる。データメンバの変更に特化したものはセッター(''setter'')ミューテイタ(''mutator'')と呼ばれる。メソッドは、クラスメソッドとインスタンスメソッドに分かれる。クラスメソッドは静的メソッドとも呼ばれる。クラスメソッドはクラス名の名前空間でスコープされたグローバル関数と同じものである。インスタンスメソッドを呼び出すには、そのメソッドが属するインスタンス参照が必要になる。これはthisインスタンスと呼ばれる。プロトタイプベースではプロトタイプオブジェクトが保持する特定のメソッドが静的メソッドに該当するものになる。 |
|||
;[[オーバーロード]] |
|||
=== [[コンストラクタ]] === |
|||
:(''overloading'')は一つのメソッド名に複数の異なるパラメータリスト(引数欄)を付けたものを列挙してメソッド名を多重定義すること。[[演算子]]もオーバーロード対象であり、[[単項演算子]]なら一つの引数の型、[[二項演算子]]なら二つの引数の型を多重定義することで演算対象の値の型ごとに計算内容をカスタマイズできる。特筆的なものに[[クロージャ]]=[[関数オブジェクト]]を表現する ( )演算子がありこれは任意個数の引数を多重定義できる。インスタンス自体を任意構成の引数とともに関数のように使える仕組みである。 |
|||
(''constructor'')はインスタンス生成時に呼び出されるそのクラスのメソッドである。インスタンスデータメンバを任意の値で初期化するためのものであるが、その他の初期化コードも記述できる。プロトタイプベースではプロトタイプオブジェクトと同名のグローバル関数として存在している。 |
|||
;[[オーバーライド]] |
|||
:(''method overriding'')は継承による階層的クラス構造のインスタンスにおいて、サブクラスのメソッドシグニチャの処理内容でそのスーパークラス側の同じメソッドシグニチャの処理内容を置き換える仕組みを指す。メソッドシグニチャとは「返り値+メソッド名+引数欄」で構成される識別単位である。この指定は親側のメソッドが上書きされるのをデフォルトにするのと、子側のメソッドで上書きするのをデフォルトにする二通りがある。前者なら子側のメソッドを''override''や''redefine''で修飾しそれで親側メソッドを上書きする。後者なら親側のメソッドを''virtual''や''deferred''や''abstract''で修飾しそれは子側メソッドで上書きされる。それとは別にただメソッドを上書き不可にする場合は''final''などで修飾する。 |
|||
(''destructor'')はインスタンス破棄時に呼び出されるそのクラスのメソッドである。インスタンス破棄の影響を解決する任意の後始末コードを記述できる。インスタンスの破棄は占有メモリの解放を意味する。なお、ガーベジコレクタ実装言語ではファイナライザになっている事がある。プログラマが呼び出すデストラクタの方はその終了がメモリ解放に直結してるのに対し、ガーベジコレクタが呼び出すファイナライザの方はそうではない。 |
|||
;[[ジェネリクス]] |
|||
=== アクセスコントロール === |
|||
:(''generics'')はクラス内のデータメンバの型、メソッドの引数の型、返り値の型を総称化して型変数とし、任意の具体的な型を型引数にしてコンストラクタを呼び出して、型変数に型引数を当てはめて(適用)インスタンスを生成する仕組みを指す。クラス内の型の決定をコンストラクタまで先送りする手法である。このジェネリッククラスに対して、引数の型と返り値の型を総称化したジェネリック関数もある。型変数をバリアンスにすることで適用クラスの派生クラスも当てはめることができる。型変数のバリアンスを用いないジェネリクスの方は特にテンプレートと呼ばれる。 |
|||
(''access control'')はカプセル化に基づくデータメンバとメソッドの可視性を決定するものである。可視性はプライベート、プロテクト、パブリックの三種が基本である。プライベートは同クラス内のみ、プロテクトは同クラス内と派生クラス内のみ、パブリックはどこからでもアクセス可能である。 |
|||
;[[テンプレート (プログラミング)|テンプレート]] |
|||
:(''template'')は型変数のバリアンスを用いない方のジェネリクスを指す。コンパイル時にそれぞれのテンプレートクラスおよびテンプレート関数の型変数(仮型引数)部分に、それぞれの生成箇所の型引数(実型引数)を当てはめたソースコードがそのまま複製される仕組みである。 |
|||
(''interface'')はプログラム概念と機能名の双方を指す用語である。言語によってはプロトコルと言われる。抽象メソッドと具象メソッド(実装内容付き)で構成される純粋抽象~半抽象クラスを意味する。クラスの振る舞い局面を抽出したものであり、[[統一モデリング言語|UML]]では実現と言われる。クラスによるインターフェースの継承は実装と呼ばれる。多重実装可が普通である。ミックスインとの違いは、抽象階層に焦点が当てられている事であり、直下の実装オブジェクトを共通の振る舞い局面でまとめることがその役割である。インターフェースは自身の実装オブジェクトをグループ化できる。{{仮リンク|記名的型付け|en|Nominal type system|label=}}に準拠しているのでインターフェースの実装の明記が振る舞い局面の識別基準になる。インターフェースは抽象メソッド主体なので多重継承時のメンバ名の重複はあまり問題にならない。共通の実装メソッドに集約されるからである。インターフェースはインスタンス化されない。 |
|||
;[[共変性と反変性 (計算機科学)|バリアンス]] |
|||
=== [[ミックスイン]] === |
|||
:(''variance'')は、あるクラスで型注釈された箇所にそれと継承関係があるクラスも適用できるようにする仕組みである。注釈クラスとその派生クラスを適用できるようにしたのは共変性と呼ばれる。注釈クラスとその基底クラスを適用できるようにしたのは反変性と呼ばれる。オブジェクト指向下のバリアンスは、もっぱらジェネリクスのカテゴリで用いられジェネリッククラスの型変数が対象になる。バリアンスはジェネリッククラスの継承構造上のオーバーライドで様々に応用される。 |
|||
(''mixin'')はインターフェースに似たプログラム概念を指す用語である。機能名は言語によって[[トレイト]]またはプロトコルと言われる。抽象&具象メソッドとデータメンバで構成される継承専用クラスを意味する。クラスを特徴付けるための装飾部品である。クラスによるトレイトの継承は実装と呼ばれる。多重実装可が普通である。インターフェースとの違いは、トレイトの実装階層に焦点が当てられている事であり、オブジェクトを所有メンバで特定してまとめることがその役割である。トレイトは自身の[[上位集合]]であるオブジェクトをグループ化できる。{{仮リンク|構造的型付け|en|Structural type system|label=}}に準拠しているので所属メンバ構成自体がトレイト等価性の識別基準になる。これはトレイト実装を明記してなくても、そのトレイトが内包する全メンバを所持していれば同じトレイトと見なされることを意味する。トレイトは多重継承時のメンバ名重複の際にその参照の優先順位に注意する必要が出てくる。トレイトはインスタンス化されない。 |
|||
;型制約 |
|||
=== [[メタクラス]] === |
|||
:(''type constraint'')はジェネリッククラスの型引数ないし型変数、または代入値の型が実行時に決められる動的束縛型に用いられるものである。それぞれを指定クラスで記号修飾して、型引数と型変数では指定クラスの派生クラスのみを適用できるようにし、動的束縛型では指定クラスの派生クラス値のみが代入できるようにする仕組みである。これは型境界(''type bound'')とも呼ばれる。 |
|||
(''metaclass'')とはクラスを定義しているクラスであるが、その実態はシステム側が用意している特別なシングルトンオブジェクトと考えた方が分かりやすい。システム内のクラス定義情報をクラスに見立てて、それをインスタンス化したものである。慣例的にこれをメタクラスと呼ぶ。メタクラスはクラスのデータメンバとメソッドの定義情報を指し、それを操作する機能はリフレクションと呼ばれる。クラスベースで用いられるものである。 |
|||
;コンポジション |
|||
=== [[リフレクション (情報工学)|リフレクション]] === |
|||
:合成(''composition'')は強い[[has-a]]関係。AクラスがBクラスをデータメンバにし、Aのコンストラクタと同時にBインスタンスが生成され、Aのデストラクタと同時にBインスタンスが破棄される場合、AはBの合成となる。Bが自身のサブクラスで交換される場合は分離とともに破棄される。 |
|||
(''reflection'')はクラスの定義情報を変更する機能であるが、言語ごとに変更できる定義情報の範囲は異なっている。データメンバではデータ型、識別子、可視性が変更対象になる。メソッドではリターン型、識別子、パラメータリスト、可視性、仮想指定が変更対象になる。双方の追加定義と削除もできる事がある。スーパークラスも変更できる事がある。また、実行時の文字列(char配列やString)をデータメンバとメソッドの内部識別子として解釈できる機能もリフレクションに当たる。これは実行時の文字列によるデータメンバの参照とメソッドの呼び出しを可能にする。 |
|||
;アグリゲーション |
|||
=== 遅延バインディング === |
|||
:集約(''aggregation'')は弱い[[has-a]]関係。AクラスがBクラスをデータメンバにし、Aクラスのコンストラクタとは関係なくBインスタンスが生成され、AクラスのデストラクタでBインスタンスが破棄されず、また分離時も破棄されない場合、AはBの集約となる。Aクラスがコレクション(配列、List、Set、Map)の仕組みでBインスタンスを持つ場合も、AはBの集約となる。コレクション性を強調する場合は収容(''containment'')とすることもある。 |
|||
(''late binding'')は、識別子が参照するオブジェクトをコンパイル時に決める事前バインディング(''early binding'')の対義語であり、この場合は識別子の参照先を実行時に決める動的バインディングとほぼ同じ意味で用いられる。一方で、特にリフレクション機能を通して実装される方を遅延バインディングとする考え方もある。抽象化された型に対して、実行時の文字列(char配列やString)を内部識別子に解釈し、コンパイル時には認識されていなかったオブジェクトをローディングして代入する仕組みなどである。オブジェクトの呼び出しが、[[ダイナミックリンクライブラリ|DLL]]やクラスライブラリの動的ローディングに繋がることが遅延バインディングと呼ばれる基準になる。[[ストアドプロシージャ]]の動的ロード、代入、呼び出しもそれに当たる。ローディング基準が外される例では、プログラム内でデータとして扱われている[[コードブロック]]を関数の型に代入して呼び出すという仕組みがある。そのコードブロックは文字値と数値の混合配列であり、リフレクション機能を利用して実行する。 |
|||
;アソシエーション |
|||
=== 動的ディスパッチ === |
|||
:関連(''association'')。AクラスがBクラスのメソッドを呼び出す場合、AはBに関連しているとなる。AはBへの誘導可能性を持つとされる(A→B)。has-a関係で保有しているインスタンスのメソッドを呼び出すという意味で関連線は合成線または集約線と重ねて引かれることが多い。 |
|||
(''dynamic dispatch'')はメソッドの呼び出しを受けるオブジェクトの側に焦点を当てたプログラム概念である。一般的なローカルメソッドでは、メソッド識別子にマッピングされている参照が指すメソッド実体を呼び出す仕組みを意味する。参照が指す先はプログラム実行中に随時変更されるのでコンパイル時ではなく実行時のその都度に確定されることになる。リモートメソッドでは、受け取ったバイトデータ列を解釈しリフレクション機能でメソッドを呼び出す仕組みを意味する。受信側の実行時状態による選択が加えられる事もある。始めのアクセスで所有メソッドリストを呼び出し側に送り、無駄なエラーリクエストを無くす仕組みと併用される事が多い。 |
|||
;ディペンデンシー |
|||
:依存(''dependency'')。AクラスのメソッドがBクラスのインスタンスを引数または返り値にしてる場合、AはBに依存しているとなる。返り値の例として、Aのメソッドがその返り値としてBインスタンスを生成する場合も、AはBに依存しているとなる。 |
|||
;[[委譲|デリゲーション]] |
|||
=== [[動的束縛|動的バインディング]] === |
|||
:委譲(''delegation'')は基本例としては、呼び出されたあるクラスのメソッドが自分への引数を他のクラスの同名メソッドにそのまま渡して、その同名メソッドの返り値をそのまま呼び出し元に返すという仕組みを指す。委譲先となる他のクラスはhas-a関係で保有されているものが使われる。委譲先メソッドは必ずしも同名ではなくマッピング名の場合もあり、引数も構成を変えて渡される場合もある。 |
|||
(''dynamic binding'')は特定の識別子から呼び出されるメソッドないし参照されるデータメンバが、コンパイル時ではなく実行時に決められる仕組み全般を指す用語である。プロトタイプベースのオブジェクトからメソッドとデータメンバが参照される機構、仮想関数メソッドから派生クラスのメソッドが呼び出されるシングルディスパッチ機構、メソッドに渡された実引数を実行時型チェックしてその結果に従いプロセスを分岐させるシングルディスパッチ~多重ディスパッチ機構などが例である。 |
|||
== 脚注 == |
== 脚注 == |
||
168行目: | 181行目: | ||
== 関連項目 == |
== 関連項目 == |
||
{{Wikibooks|オブジェクト指向|オブジェクト指向}} |
{{Wikibooks|オブジェクト指向|オブジェクト指向}} |
||
*[[委譲]] |
|||
{{Normdaten}} |
{{Normdaten}} |
2020年8月26日 (水) 06:48時点における版
![]() |
![](http://upload.wikimedia.org/wikipedia/commons/thumb/d/d0/Object_oriented_design_object.jpg/220px-Object_oriented_design_object.jpg)
プログラミング・パラダイム |
---|
オブジェクト指向プログラミング(オブジェクトしこうプログラミング、英: object-oriented programming、略語:OOP)とは、互いに密接な関連性を持つデータとメソッドをひとつにまとめてオブジェクトとし、それぞれ異なる性質と役割を持たせたオブジェクトの様々な定義と、それらオブジェクトを相互に作用させる様々なプロセスの設定を通して、プログラム全体を構築するソフトウェア開発手法である。
オブジェクト指向という用語自体は、計算機科学者アラン・ケイによって生み出されている。1962年公開の言語「Simula」の設計に印象を受けたケイが咄嗟に口にしたとされるこの造語は、彼が1972年から公開を始めた「Smalltalk」の言語設計を説明する中で初めて世間に発信された。なお、ケイが示したメッセージパッシングを中心にするオブジェクト指向は広く認知される事はなく、オブジェクトというプログラム概念を注目させるだけに留まっている。同時にケイの手から離れたオブジェクト指向は抽象データ型を中心にした解釈へと推移していき、1983年に計算機科学者ビャーネ・ストロヴストルップが公開した「C++」が契機になって、日本では一般にOOPの三大要素と呼ばれるカプセル化、継承、多態性といったパラダイムが確立されている。
特徴
現行のオブジェクト指向プログラミングは、1974年に計算機科学者バーバラ・リスコフらが提唱した抽象データ型を基礎的な考え方にする方向性で定着している。抽象データ型のプログラム実装スタイルを具体的に規定したものが1~3であり、日本では一般に三大要素と呼ばれている。これに沿った言語仕様を備えたプログラミング言語がオブジェクト指向準拠と判別されている。4はアラン・ケイが重視する元祖的なコンセプトであり、オブジェクト指向の源流思想として蛇足ながら紹介を加える。
- カプセル化(encapsulation)
- 継承(inheritance)
- 多態性(polymorphism)
- メッセージパッシング(message passing)
カプセル化
一定の関連性を持つデータ(変数、プロパティ、フィールド)と、それらを操作するメソッド(関数)をひとまとめにしてオブジェクトとし、外部に対して必要とされるデータとメソッドのみを公開し、それ以外を内部に隠蔽する仕組みがカプセル化と呼ばれる。公開されたデータは外部のメソッドから直接参照ないし変更する事できる。公開されたメソッドは外部のメソッドから直接呼び出す事ができる。隠蔽されたデータとメソッドは外部からアクセスできず、これは情報隠蔽と呼ばれる。メソッドを通してデータを参照ないし変更する仕組みはデータの抽象化を表現する。データを参照するメソッドはゲッターまたはアクセッサと呼ばれる。データを変更するメソッドはセッターまたはミューテイタと呼ばれる。
継承
既存オブジェクトのデータ構成とメソッド構成を引き継いで、新しい派生オブジェクトを定義する仕組みが継承と呼ばれる。引き継ぐ際には新たなデータとメソッドを自由に追加できるので、派生オブジェクトの構成は既存内容+追加内容になる。既存オブジェクトは親オブジェクト、派生オブジェクトは子オブジェクトとも呼ばれる。クラスベースでは、親をスーパークラス、子をサブクラスと呼ぶ。一つのスーパークラスを継承するのは単一継承と呼ばれる。複数個のスーパークラスを継承してそれぞれの構成内容を引き継ぐのは多重継承と呼ばれる。抽象化に注目した継承の方は、UMLでは実現と呼ばれるものになる。これは一定のオブジェクトに共通した振る舞い局面を抜き出して抽象化する仕組みを指し、その抽象化オブジェクトはインターフェース、トレイト、プロトコルなどと呼ばれる。
多態性
異なる種類のオブジェクトに同一の操作インターフェースを持たせる仕組みが多態性と呼ばれる。オブジェクト指向視点の多態性は、クラスの派生関係またはオブジェクトの動的バインディングによって、コンパイル時のメソッド名から呼び出されるプロセス内容が実行時に決定される仕組みを意味するサブタイプ多相を指す。オブジェクト指向のサブタイプ多相はクラスベースの仮想関数と、プロトタイプベースの動的ディスパッチの二手法に大別される。仮想関数は、メソッドが所属するクラスの派生関係のみに焦点を当てた単一ディスパッチであり、スーパークラス抽象メソッドへの呼び出しから、それをオーバーライドしたサブクラス実装メソッドに分岐させる機能を指す。その際は各メソッドへのポインタを並べた仮想関数テーブルと呼ばれる仕組みが用いられる。単一ディスパッチとはプロセス分岐に関与するオブジェクトが一つであることを意味しており、二つ以上の場合は多重ディスパッチになる。多重の方はメソッドが属するクラスの派生関係だけでなく、そのメソッドの各引数のクラスの派生関係にも注目した形態であり、各引数は実行時に型ダウンキャストされてそれらの引数型の組み合わせに対応したプロセスに分岐する。メソッドが属するクラスの派生関係が絡まない場合は単一引数だと単一ディスパッチになる。動的ディスパッチは、プロトタイプベースのオブジェクトのメソッド名スロットに当てはめられるメソッド実装の参照が随時切り替えられることで、そのメソッド名から呼び出されるプロセスが実行時に決定されるという仕組みを指す。クラスベースの方ではリフレクション機能によって同様に、メソッド名から呼び出されるプロセス内容が実行時に決まるという仕組みが実装される。
メッセージパッシング
I thought of objects being like biological cells and/or individual computers on a network, only able to communicate with messages.
(さながら生物の細胞、もしくはネットワーク上の銘々のコンピュータ、それらはただメッセージによって繋がり合う存在、僕はオブジェクトをそう考えている) — Alan Kay
... each object could have several algebras associated with it, and there could be families of these, and that these would be very very useful.
(銘々のオブジェクトは自身に伴う幾つかの「代数」を持つ、またそれらの家族たちもいるかもしれない、それらは極めて有用になるだろう) — Alan Kay
The Japanese have a small word - ma ... The key in making great and growable systems is much more to design how its modules communicate rather than what their internal properties and behaviors should be.
(日本語には「間」という言葉がある・・・成長的なシステムを作る鍵とは内部の特徴と動作がどうあるべきかよりも、それらがどう繋がり合うかをデザインする事なんだ) — Alan Kay
I realized that the cell/whole-computer metaphor would get rid of data, ...
(僕はこう気付いた、細胞であり全体でもあるコンピュータメタファーはデータを除去するであろうと、) — Alan Kay
... there were two main paths that were catalysed by Simula. The early one (just by accident) was the bio/net non-data-procedure route that I took. The other one, which came a little later as an object of study was abstract data types, and this got much more play.
(Simulaを触媒にした二本の道筋があった。初めの一本はバイオネットな非データ手法、僕が選んだ方だ。少し遅れたもう一本は抽象データ型、こっちの方がずっと賑わってるね。) — Alan Kay
歴史
1954年に初の高水準言語・FORTRANが登場すると、開発効率の劇的な向上と共にソフトウェア要求度も自然と高まりを見せてプログラム規模の急速な拡大が始まった。それに対応するために肥大化したメインルーチンをサブルーチンに分割する手法と、スパゲティ化したgoto命令を制御構造文に置き換える手法が編み出され、これらは1960年に公開された言語「ALGOL60」で形式化された。当時のALGOLはアルゴリズム記述の一つの模範形と見なされたが、それと並行して北欧を中心にした計算機科学者たちはより大局的な観点によるプログラム開発技法の研究を進めていた。
Simulaの開発(1962~72)
1962年、ノルウェー計算センターでモンテカルロ法シミュレーションを運用していた計算機科学者クリステン・ニゴールは、ALGOL60を土台にしてProcessと呼ばれるコルーチン機構を加えたプログラミング言語「Simula」を公開し、続けてその拡張にも取り組んだ。ニゴールの同僚で、1963年にSimulaを汎用機UNIVAC系統上で運用できるように実装した計算機科学者オルヨハン・ダールは、Processにローカル変数構造を共有する複数の手続き(サブルーチン)を加えてパッケージ化する言語仕様を考案した。程なくしてALGOL60コンパイラに準拠していての限界を悟ったニゴールとダールは、1965年からSimulaを一から再設計するように方針転換した。その過程で彼らは、計算機科学者アントニー・ホーアが考案して1962年のSIMSCRIPT(FORTRAN用のスクリプト)に実装していたRecord Classを参考にしている。Record Classはソースコード水準の抽象表現を、各汎用機に準拠したマシンコード水準の実装符号に落とし込む段階的データ構造のプログラム概念であった。これをモデルにした継承とその構造上に成り立つ仮想手続き(仮想関数)の仕組みも考案され、この両機能を備えたProcessのパッケージ化を「クラス」とし、クラスをメモリに展開したものを「オブジェクト」とする言語仕様がまとまり、1967年に「Simula67」が初公開された。オブジェクトという用語は、MITの計算機科学者アイバン・サザランドが1963年に開発したSketchpad(CADとGUIの元祖)の設計内にあるObjectが先例であった。Simula67コンパイラはまずUNIVAC上で運用され、翌年から汎用機バロースB5500などでも稼働されて北欧、ドイツ、ソ連の各研究機関へと広まり、1972年にはIBM汎用機System/360などにも導入されて北米全土にも広まった。その主な用途は物理シミュレーションであった。
構造化プログラミングの提唱(1969~75)
Simulaの普及と前後して1960年代半ばになると、プログラム規模の際限ない肥大化に伴う開発現場の負担増大が顕著になり、いわゆるソフトウェア危機問題が計算機科学分野全般で取り沙汰されるようになった。その解決に取り組んだ計算機科学者エドガー・ダイクストラは、1969年のNATOソフトウェア工学会議で「構造化プログラミング」という論文を発表しトップダウン設計、段階的な抽象化、階層的なモジュール化、共同詳細化といった構造化手法を提唱した。ダイクストラの言う構造化とは開発効率を高めるための分割統治法を意味していた。なおこの構造化プログラミングは後に曲解されて制御構造文を中心にした解釈の方で世間に広まり定着している。共同詳細化は抽象データ構造を専用サブルーチンを通して扱うという概念である。これはSimulaの手続きを通してクラス内の変数にアクセスするという仕組みをモチーフにしていた。段階的な抽象化と階層的なモジュール化は時系列的にも、SIMSCRIPTの段階的データ構造と、Simura67の継承による階層的クラス構造を模倣したものであった。ダイクストラ、ホーア、ダールの三名は1972年に『構造化プログラミング』と題した共著を上梓していることから互いの研鑽関係が証明されている。その階層的プログラム構造という章の中でダールは、Simulaの目指した設計を更に明らかにした。
1974年にMITの計算機科学者バーバラ・リスコフとステファン・ジルは「抽象データ型」というプログラム概念を提唱した。彼女らの理論は、ダイクストラが提示したモジュールの共同詳細化を、振る舞い意味によって定義される抽象データという考え方でより明解に形式化し、データ階層ないしモジュール階層の連結関係を、上位概念と下位概念の置き換え原則で明確に標準化した。一方、1970年に構造化言語Pascalを開発していた計算機科学者ニクラウス・ヴィルトは、ダイクストラによる共著出版後の1975年にモジュール化言語Modulaを提示してモジューラプログラミングというパラダイムを生み出している。このようにいささか奇妙ではあるが、Simulaのクラスとオブジェクトというプログラム概念は、巷で言われる構造化からモジュール化へといった進化の流れとは関係なく、しかもその前段階においてさながら彗星のように生まれたパラダイムであった。
Smalltalkとオブジェクト指向の誕生(1972~81)
初代SimulaからのProcessの仕様は、パロアルト研究所の計算機科学者アラン・ケイによるオブジェクトと「メッセージ」というプログラム概念のヒントになった。ケイはプログラム内のあらゆる要素をオブジェクトとして扱い、オブジェクトはメッセージの送受信でコミュニケーションするという独特のプログラム理論を提唱した。メッセージとはプログラムコードとしても解釈できるデータ列のことであり、そのデータ列を評価(eval)することで新たなデータを導出できるという仕組みを意味していた。抽象データを扱うサブルーチンを更に抽象データ化したようなスタイルである。オブジェクトが受け取ったメッセージは任意のタイミングで評価できるので非同期通信、単方向通信(送りっぱなし処理)をも可能にしていた。この発想の背景にはLISPの影響があった。オブジェクトとメッセージの構想に基づいて開発された「Smalltalk」はプログラミング言語とGUI運用環境を併せたものとなり、1972年にゼロックスAlto上で初稼働された。Smalltalkの設計を説明するためにケイが考案した「オブジェクト指向」という用語はここで初めて発信された。またメッセージの構想はMITの計算機科学者カール・ヒューイットに能動的なプロセス代数を意識させて、1973年発表のアクターモデルのヒントにもなっている。しかし、データ列が常にコード候補として扱われる処理系は、当時のコンピュータには負荷が大きく実用的な速度を得られないという問題にすぐ直面した。Smalltalk-74とSmalltalk-76の過程で、やむなくメッセージはセレクタ仕様の追加と共に構想通りの評価ができないほどシステム向けに最適化され、レシーバーは動的ディスパッチとメソッド仕様が中心になり、オブジェクトはクラス定義の存在感が大きくなった。
Smalltalk is not only NOT its syntax or the class library, it is not even about classes. I'm sorry that I long ago coined the term "objects" for this topic because it gets many people to focus on the lesser idea.The big idea is "messaging".
(Smalltalkはその構文やライブラリやクラスをも関心にしていないという事だけではない。多くの人の関心を小さなアイディアに向かせたことから、僕はオブジェクトという用語を昔作り出したことを残念に思っている。大切なのはメッセージングなんだ。) — Alan Kay
1980年のSmalltalk-80は、元々はメッセージを重視していたケイを自嘲させるほど同期的で双方向的で手続き的なオブジェクト指向へと変貌していた。それでも動的ディスパッチと委譲でオブジェクトを連携させるスタイルは画期的であり、1994年に発表されるデザインパターンの模範にもされている。1981年に大手専門誌BYTE MagazineがSmalltalkとケイ提唱のオブジェクト指向を紹介して世間の注目を集める契機になったが、ケイの思惑に反して技術的関心を集めたのはクラス機構の方であった。オブジェクト指向は知名度を得るのと同時に、Simula発のクラスとそれを理論面から形式化した抽象データ型を中心に解釈されるようになり、それらの考案者がケイの構想とは無関係であったことから、オブジェクト指向の定義はケイの手を離れて独り歩きするようになった。
C++の開発(1979~86)
Simulaを研究対象にしていたAT&Tベル研究所の計算機科学者ビャーネ・ストロヴストルップは、1979年からクラス付きC言語の開発に取り組み、1983年に「C++」を公開した。C++で実装されたクラスは、Simula譲りの継承と仮想関数に加えて、モジューラプログラミングのデータ隠蔽をモデルにしたアクセスコントロールを備えていた。C++で確立されたアクセスコントロールはカプセル化の元になったがコードスタイル上ほとんどザル化されており、その理由からストロヴストルップ自身もC++は正しくない(not just)オブジェクト指向言語であると明言している。1986年にソフトウェア技術者バートランド・メイヤーが開発した「Eiffel」の方は、正しいオブジェクト指向を標榜してクラスのカプセル化を遵守させるコードスタイルが導入されていた。クラスメンバは属性、手続き、関数の三種構成で、手続きで属性を変更し関数で属性を加工参照するという形式に限定されており、これは抽象データ型の振る舞い意味論に沿った実装であった。アクセスコントロールはC++のアクセス修飾子による段階的スコープ定義に対して自身のクライアントクラスを定義する書式になり、また契約による設計に沿ったきめ細かなアサーション機能が備えられていた。前者は結合度、後者は凝集度の面からカプセル化を補強した。C++の仮想関数は延期関数の名で実装された。
I made up the term ‘object-oriented’, and I can tell you I didn’t have C++ in mind.
(僕はオブジェクト指向という言葉を作った、それとC++に関心がなかったことも分かっている) — Alan Kay
1986年からACMはオブジェクト指向会議(OOPSLA)を開催し、そのプログラミング言語セクションではクラス・パラダイムのオブジェクト指向の意見交換が中心になされ、Eiffelを現行の模範形とする声が多く上がった。しかし世間のプログラマの間では厳格なEiffelよりも、柔軟で融通の利くC++の人気の方が高まっていた。この頃に専用サブルーチンを通したデータ抽象とアクセスコントロールの概念はカプセル化という用語に一般化され、仮想関数ないし延期関数は多態性という用語に包括された。こうして元からの継承と合わせていわゆるオブジェクト指向の三大要素が確立された。同時に多重継承の問題も指摘され始めインターフェースという設計が取り上げられることになる。また、Smalltalkが標榜するメッセージ・メタファも単にオブジェクト指向の発案元であるという理由から一目置かれており、クラスのメソッドの呼び出しにこれを当てはめようとする考え方が一般化した。他方でSmalltalkの仕様に忠実であろうとする動きもあり、1984年に計算機科学者ブラッド・コックスが開発した「Objective-C」はSmalltalkをモデルにしてそれを平易化した言語であった。そのメッセージレシーバーはメソッドリストにないセレクタを受け取った場合のみに動的ディスパッチ機構に移るというスタイルで形式化された。程なくしてこのメッセージレシーバー実装の必要性には疑問符が付けられるようになったが、遠隔手続き呼出しのスタイルにはマッチしていたのでメッセージにある種の理想を抱く風潮はいつまでも残った。
プロトタイプベースの考案(1985~90)
Smalltalkのオブジェクト指向は、アラン・ケイがその影響を言及していたLISPコミュニティを逆に感化して、Smalltalkが改めて提示したメタオブジェクトの概念を通したオブジェクト指向とLISP風プログラミングの連携に向けた構想が練られるようになった。LISPにはアトムとシンボル型というキーファクターが存在していたので、それと同様にオブジェクトのメンバ変数名とメンバ関数名自体をその都度評価(eval)して実行時の内容を導出し、実際の変数参照や関数呼出につなげるというアイディアが生まれた。これは実装面では単に、フレームと呼ばれる動的配列のスロットに変数や関数のポインタを付け替えするという機構にまとめられた。識別子(変数名と関数名)がマッピングされたスロットも増設削減可能であり、原型クラスと継承クラスのポインタも加えられた。このメタオブジェクト設計を導入して1985年にMIT人工知能研究所のLISPマシン上で「Flavors」が実装された。LISPの視点から保有スロット識別子の構成による動的型付けが盛り込まれ、それと多重継承を合わせたミックスインという設計が考案され、更にそれを平易化したダックタイピングの概念も自然発生した。1988年にFlavorsのデザインをCommon Lispに融合させた「CLOS」が公開されたが、こちらは関数を中心にした一風変わったスタイルになった。Flavorsのデザインはパロアルト研究所にも回帰され、計算機科学者デビッド・アンガーがSmalltalkの方言として制作する「Self」を1987年に初回リリースした。LISPコミュニティから逆輸入されてSelfに導入されたメタオブジェクト設計は、後にプロトタイプベースまたはインスタンスベースと呼ばれるパラダイムに発展し、WEBプログラム時代を迎えて大幅にプログラマ人口を増やしたオブジェクト指向スクリプト言語に大きな影響を与える事になった。同時にそれと、従来のクラスの仕組みを用いるオブジェクト指向言語を区別するためのクラスベースという言葉も生まれた。
代表的なオブジェクト指向言語
オブジェクト指向言語は、抽象データ型の仕組みに沿ったクラスベース、フレームとスロットの仕組みに沿ったプロトタイプベース、Smalltalkをルーツにしたメッセージ構文ベースの三タイプに分類されるのが一般的である。クラスベースでは「C++」「Java」「C#」が代表的である。プロトタイプベースでは「Python」「JavaScript」「Ruby」が有名である。メッセージ構文ベースでは「Smalltalk」「Objective-C」「Self」などがある。言語仕様の中でオブジェクト指向の存在感が比較的高い代表的なプログラミング言語は以下の通りである。
![](http://upload.wikimedia.org/wikipedia/commons/thumb/6/67/History_of_object-oriented_programming_languages.svg/220px-History_of_object-oriented_programming_languages.svg.png)
- Simula 67 1967年
- 1962年に公開されたSimulaの後継版であり、クラスのプログラム概念を導入した最初の言語である。物理モデルを解析するシミュレーション制作用に開発されたもので、クラスをメモリに展開したオブジェクトはその観測対象要素になった。Simulaのクラスは、一つのローカル変数構造と複数のプロシージャをまとめたミニモジュールと言えるものであったが、継承と仮想関数という先進的な設計を備えていた事でオブジェクト指向言語の草分けと見なされるようになった。クラスベースの源流である。
- Smalltalk 1972年
- メッセージパッシングのプログラム概念を導入した最初の言語。数値、真偽値、文字列から変数、コードブロック、メタデータまでのあらゆる要素をオブジェクトとするアイディアを編み出した最初の言語でもある。オブジェクト指向という言葉はSmalltalkの言語設計を説明する中で生み出された。オブジェクトにメッセージを送るという書式であらゆるプロセスを表現することが目標にされている。メッセージレシーバーと委譲の仕組みは、形式化されてない動的ディスパッチと動的バインディング相当のものでありプロトタイプベースの源流にもなった。専用のランタイム環境上で動作させる設計も模範にされ、これは後に仮想マシンや仮想実行システムと呼ばれるものになる。
- C++ 1983年
- C言語にクラスベースのオブジェクト指向を追加したもの。Simulaの影響を受けている。静的型付けのクラスが備えられて、カプセル化、継承、多態性の三仕様を実装している。カプセル化はアクセス修飾子とフレンド指定子の双方を定義できる。継承は多重継承、オーバーライド制約用の継承可視性、菱形継承問題解決用の仮想継承も導入されている。多態性は仮想関数によるサブタイプ多相、テンプレートクラス&関数によるパラメトリック多相、関数&演算子オーバーロードによるアドホック多相が導入されている。元がC言語であるため、オブジェクト指向から逸脱したコーディングも多用できる点が物議を醸したが、その是非はプログラマ次第であるという結論に落ち着いた。
- Objective-C 1984年
- C言語にメッセージ構文ベースのオブジェクト指向を追加したもの。こちらはSmalltalkの影響を受けており、それに準じたメッセージパッシングの書式が備えられた。メッセージを受け取るクラスの定義による静的型付けと共に、メッセージを委譲するオブジェクトの実行時決定による動的型付けも設けられている。オブジェクト指向的にはC++よりも正統と見なされた。制御構造文が追加され、メッセージを送る書式も平易化されており、Smalltalkよりも扱いやすくなった。
- Object Pascal 1986年
- Pascalにクラスベースのオブジェクト指向を追加したもの。当初はモジュールのデータ隠蔽的なカプセル化、単一継承、仮想関数による多態性という基本的なものだった。静的型付け重視である。関数&演算子オーバーロード(アドホック多相)とジェネリクス(パラメトリック多相)は当初採用に到らなかった。ヴィルト監修のアップル社による初回バージョンを基礎にして様々な企業団体による派生版が公開されており、その特徴と機能追加も様々である。
- Eiffel 1986年
- C++の柔軟性と融通性とは正反対のオブジェクト指向言語。クラスベースで静的型付け重視である。契約プログラミングを理念にしており、アサーションの挿入でクラスの状態とメソッド引数&返り値を細かくチェックできる。クラスメンバ(フィーチャー)は属性、アクセッサ、ミューテイタの三種限定でオーバーロードはできない。カプセル化の可視性は自身に依存するクラス(クライアント)を定義するという形で決められる。多重継承可能であり、クラス間の繋がりを仮想継承機能、各種オーバーライド指定子、名前衝突を解決するリネーミング機能などで綿密に設定できる。延期関数(仮想関数)とテンプレート相当のジェネリッククラスも導入されている。ガーベジコレクション機能が初めて導入されたオブジェクト指向言語でもある。
- Self 1987年
- メッセージ構文ベースのオブジェクト指向言語。標準配備のオブジェクトを複製して、そのスロットに任意のプロパティとメソッドを動的バインディングできるというプロトタイプベースを初めて導入したオブジェクト指向言語でもある。ゆえに動的型付け重視である。当初はSmalltalkの派生言語として公開されており、それと同様に専用のランタイム環境上で実行され、GUI運用環境の構築も目標にしていた。Selfのランタイム環境は実行時コンパイラ機能を初めて実装したことで知られており画期的な処理速度を実現している。この技術はJava仮想マシンの土台になった。
- CLOS 1988年
- Common Lispにプロトタイプベースに似たオブジェクト指向を追加したもの。構造体オブジェクトと多重定義関数オブジェクトに分離されており、前者のスロットには任意のフィールドを、後者のスロットには任意のパラメータパターンを動的バインディングできる動的型付け重視である。動的型付けの構造体オブジェクトを引数として渡される関数の多重ディスパッチが重視されている。
- Python 1994年
- プロトタイプベースとクラスベースの双方を兼ねたオブジェクト指向スクリプト言語。静的型付けのクラスと動的型付けのインスタンスが併用されているが、後者の動的バインディングの比重が大きめである。ダックタイピングを重視する方針により型宣言制約が撤廃されている。多態性は動的ディスパッチを中心にし、メソッドシグネチャと関数プロトタイプを操作できるリフレクションによって更に柔軟性が図られている。これらにより動的型付け重視である。ジェネリッククラスとジェネリック関数も導入されており、動的な柔軟性と静的な多様性の双方を使い分けられる。構文と書式を比較的簡素化し、インタプリタ式動作なので堅牢性も高い。
- Java 1995年
- C++をモデルにしつつ堅牢性とセキュリティを重視したクラスベースのオブジェクト指向言語。静的型付け重視である。パッケージ中心のカプセル化、単一のみの継承、仮想関数と多重実装可なインターフェースによる多態性と、基本に忠実なクラスベースである。メソッドオーバーロードと、クラスメタデータを操作できるリフレクションは初期から採用された。データコンテナ系のクラスと関数型インターフェースなどに限ってジェネリクスが導入されている。C++のポインタと値型インスタンスと演算子オーバーロードは真っ先に除外され、例外処理は残された。仮想マシン上で実行される。仮想マシンとガーベジコレクションの技術は比較的高度と見なされている。
- Delphi 1995年
- Object Pascalを発展させたもの。それと同様にこちらも基本に忠実なクラスベースで静的型付け重視であった。当初はデータベース操作プログラム開発を主な用途にして公開された。クラスとレコード(構造体)に同等の比重が置かれていた。一時期Javaの対抗馬になった。
- Ruby 1995年
- Pythonを意識して開発されたオブジェクト指向スクリプト言語。Smalltalkを一つの理想にして動的型付けを重視している。日本で誕生してグローバル化したプログラミング言語である。LISPとSmalltalkのメタプログラミング的なオブジェクト指向から、PythonとJavaScriptのプロトタイプベースなオブジェクト指向までのスタイルを幅広く取り入れており、様々な有用なプログラミング手法を採用している技のデパートのような言語である。構文と書式は平易性を旨としている。
- JavaScript 1996年
- Smalltalkの思想を受け継いでデザインされたオブジェクト指向スクリプト言語。当初はWEBアプリケーション開発を主な用途にして公開された。プロトタイプベースであり、オブジェクトを純然たるスロットの集合体として定義している。スロットにはプロパティとメソッドが動的バインディングされ、ダックタイピングで型識別される。この仕組みによる動的型付けが本命にされて、プリミティブ型以外の静的型付けが放棄されている。オブジェクトはプロトタイプのクローンであり、そのプロトタイプで分類される。プロトタイプの方は継承で体系化されている。ECMAScriptとして標準化されている。2015年版からはクラスベース向けの構文もサポートするようになった。
- C# 2000年
- Javaを強く意識してマイクロソフト社が開発したクラスベースのオブジェクト指向言語。C++のクラスの性質を残しながらマルチパラダイムに発展させている。拡張メソッドや演算子オーバーロードなどのアドホック多相的なコーディングサポートが豊富である。パラメトリック多相のジェネリクスは型変数の共変性と反変性、型引数の型制約を備えている。サブタイプ多相は、クラスは単一継承でインターフェースは多重実装と基本通りである。数々の関数型プログラミング機能も導入されている。基本は静的型付けであるが、動的束縛型(dynamic型)とダックタイピングによる動的型付けの存在感が高められているので、漸進的型付けの言語と見なされている。.NET Framework(共通言語基盤=仮想実行システム)上で実行される。
- Scala 2003年
- クラスベースのオブジェクト指向と関数型プログラミングを融合させた言語。クラス機構と関数型の型システムに同等の比重が置かれており静的型付け重視である。ミックスイン相当のトレイトとジェネリクスを連携させた多態性が重視されている。型変数のバリアンス、共変と反変双方の型境界、抽象型メンバ、オーバーライド、ジェネリックトレイト、抽象クラスの組み合わせで派生型付けされたオブジェクトは様々に体系化される。また、イミュータブルなオブジェクト(caseクラス)、オブジェクトの非交和構造(sealedクラス)、オブジェクト引数の抽出(unapplyメソッド)とオブジェクトのパターンマッチング式の組み合わせは、抽象データ型を値として扱う独特の関数型スタイルを表現できる。
- Kotlin 2011年
- Javaバイトコードを出力し、Java仮想マシン上で動作するJavaテクノロジ互換言語である。グローバル関数、グローバル変数の使用も容認されており、オブジェクト指向プログラミングを手続き型プログラミングのスタイルに崩したかのようにデザインされている。静的型付け重視である。
- TypeScript 2012年
- JavaScriptを強く意識してマイクロソフト社が開発したオブジェクト指向スクリプト言語。JavaScriptのプログラムを静的型付けで補完した言語である。クラスベース向けの構文と、関数型プログラミングの型システムのスタイルが加えられている。特に後者の性質が強調されている事から静的型付け重視である。継承構造によるサブタイプ多相はほぼ除外されており、パラメトリック多相とアドホック多相でオブジェクトを扱うというジェネリクスと型アノテーション重視の言語設計になっている。オブジェクト指向ではあるが関数型の性格が強めである。
- Swift 2014年
- Objective-Cを発展させたものであるが、メッセージ構文は破棄されており、クラスベースのオブジェクト指向になっている。オブジェクトのイミュータブル性が重視されている。単一継承が採用されているが可視性にプロテクト指定が無いので縦並びの継承は軽視されており、プロトコルの横並びの多重実装を重視している。プロトコルはインターフェースとミックスインの中間的機能であり、双方の短所を解決する様々な仕組みが導入されている。インスタンスはプロトコルを基準にして型分類され、また抽象化される。プロトコルとジェネリクスの連携による動的束縛型(Opaque型)の存在感が高められており、それと静的型付けのクラスを併用する漸進的型付けの言語と言える。
用語と解説
- クラス
- クラス(class)の仕組みを中心にしたオブジェクト指向をクラスベースと言う。クラスはデータメンバとメソッドをまとめたものであり、セマンティクスを付加された静的レコードとも解釈される。ここでのセマンティクスとはデータの用法を表わすメソッドを指す。クラスはインスタンスのひな型になる。クラスはカプセル化、継承、多態性の三機能を備えていることが求められている。カプセル化はデータメンバとメソッドの可視性を指定する機能である。継承は自身のスーパークラスを指定する機能である。多態性はオーバーライドと仮想関数テーブルを処理する機能である。コンストラクタとデストラクタの実装も必要とされている。前者はインスタンス生成時に、後者はインスタンス破棄時に呼び出されるメソッドである。
- プロトタイプオブジェクト
- プロトタイプ(prototype)の仕組みを中心にしたオブジェクト指向をプロトタイプベースと言う。プロトタイプベースで言われるオブジェクトとは、中間参照ポインタの動的配列を指す。この動的配列は一般にフレームと呼ばれる。中間参照ポインタは一般にスロットと呼ばれる。スロットにはデータメンバとメソッドの参照が代入されるので、オブジェクトはクラスと同様にデータメンバとメソッドをまとめたものになる。オブジェクトはプロトタイプオブジェクトとオブジェクトに分かれる。前者はクラス、後者はインスタンスに当たるものである。前者はシステム提供プロトタイプとユーザー定義プロトタイプに分かれる。プログラマはシステム提供プロトタイプを派生させてユーザー定義プロトタイプを作成する。プロトタイプには、規定の設計に基づいたデータメンバ参照とメソッド参照が代入されており、オブジェクトのひな型になる。プロトタイプは親プロトタイプ参照用スロットを保持しており、これは継承と類似の機能になる。プロトタイプを複製する形式でオブジェクトは生成される。オブジェクトは複製元プロトタイプと同じデータメンバとメソッドを保持しているが、生成後は任意のデータメンバとメソッドを自由に付け替えできる。オブジェクトは複製元プロトタイプ参照用スロットを保持している。複製元プロトタイプからその親プロトタイプを辿れる参照のリンクによってオブジェクトは一定の体系化がなされている。
- メッセージ
- オブジェクト指向で言われるメッセージ(message)は、複数の方面の考え方が混同されている曖昧な用語になっている。元々はSmalltalkから始まったメッセージ構文ベースのオブジェクト指向の中心機構である。以前はクラスベースの方でもメソッドの呼び出しをメッセージを送るという風に考えることが推奨されていた。メッセージはオブジェクトのコミュニケーション手段と標榜されているが、その忠実な実装内容はそれほど知られていないのが実情である。最も混同されているものにアクターモデルがあるが、そこで言われる非同期性とオブジェクト指向で言われる評価の遅延性は現行の実装スタイルではそれほど共通していない。コンポーネント準拠ソフトウェア工学とオブジェクトリクエストブローカーで言われるソフトウェアコンポーネント同士の通信もメッセージパッシングと呼ばれることが多いが、その仕様と機能は動的ディスパッチに該当するものである。メッセージのオブジェクト指向的運用はメッセージングと名付けられている。具体的な機能例としてはSmalltalk、Objective-C、Selfのメッセージレシーバーと、Rubyのメソッドミッシングなどがあるが、いずれもメッセージングの本質ではないとも言われている。
- インスタンス
- (instance)はクラスベースではクラスを実体化したものであり、実装レベルで言うとデータメンバと仮想関数テーブルをメモリ上に展開したものになる。プロトタイプベースではプロトタイプオブジェクトのクローンで生成されたオブジェクトを指す。実装レベルで言うとメモリ上に展開された中間参照ポインタの動的配列になる。
- データメンバ
- (data member)はクラスまたはオブジェクトに属する変数。言語によってフィールド、プロパティ、メンバ変数、属性と呼ばれる。データメンバは、クラスデータメンバとインスタンスデータメンバに分かれる。クラスデータメンバは静的データメンバとも呼ばれる。その中で定数化されたものはクラス定数と呼ばれる。クラスデータメンバはクラス名の名前空間でスコープされたグローバル変数と同じものであり、プログラム開始時から終了時まで確保される。インスタンスデータメンバはインスタンス生成時にメモリ上に確保されるものであり、その破棄時に消滅する。プロトタイプベースではプロトタイプオブジェクトが保持する特定のデータメンバが静的データメンバに該当するものになる。
- メソッド
- (method)はクラスまたはオブジェクトに属する関数。言語によってはメンバ関数とも呼ばれる。データメンバの参照に特化したものはゲッター(getter)アクセッサ(accessor)と呼ばれる。データメンバの変更に特化したものはセッター(setter)ミューテイタ(mutator)と呼ばれる。メソッドは、クラスメソッドとインスタンスメソッドに分かれる。クラスメソッドは静的メソッドとも呼ばれる。クラスメソッドはクラス名の名前空間でスコープされたグローバル関数と同じものである。インスタンスメソッドを呼び出すには、そのメソッドが属するインスタンス参照が必要になる。これはthisインスタンスと呼ばれる。プロトタイプベースではプロトタイプオブジェクトが保持する特定のメソッドが静的メソッドに該当するものになる。
- コンストラクタ
- (constructor)はインスタンス生成時に呼び出されるそのクラスのメソッドである。インスタンスデータメンバを任意の値で初期化するためのものであるが、その他の初期化コードも記述できる。プロトタイプベースではプロトタイプオブジェクトと同名のグローバル関数として存在している。
- デストラクタ
- (destructor)はインスタンス破棄時に呼び出されるそのクラスのメソッドである。インスタンス破棄の影響を解決する任意の後始末コードを記述できる。インスタンスの破棄は占有メモリの解放を意味する。なお、ガーベジコレクタ実装言語ではファイナライザになっている事がある。プログラマが呼び出すデストラクタの方はその終了がメモリ解放に直結してるのに対し、ガーベジコレクタが呼び出すファイナライザの方はそうではない。
- アクセスコントロール
- (access control)はカプセル化に基づくデータメンバとメソッドの可視性を決定するものである。これはスコープ基準とクライアント基準の二通りがある。スコープ基準の可視性はプライベート、プロテクト、パブリックの三種が基本である。プライベートは同クラス内のみ、プロテクトは同クラス内と派生クラス内のみ、パブリックはどこからでもアクセス可能である。クライアント基準の可視性は自クラス内のメンバへのアクセスを許可するクライアントクラスないしフレンドクラスを定義する方法で決められる。クライアントクラス指定はそのサブクラスを含むこともあり継承関係で一括定義できる。
- インターフェース
- (interface)はプログラム概念と機能名の双方を指す用語である。言語によってはプロトコルと言われる。抽象メソッドと具象メソッド(実装内容付き)で構成される純粋抽象~半抽象クラスを意味する。クラスの振る舞い局面を抽出したものであり、UMLでは実現と言われる。クラスによるインターフェースの継承は実装と呼ばれる。多重実装可が普通である。ミックスインとの違いは、抽象階層に焦点が当てられている事であり、直下の実装オブジェクトを共通の振る舞い局面でまとめることがその役割である。インターフェースは自身の実装オブジェクトをグループ化できる。記名的型付けに準拠しているのでインターフェースの実装の明記が振る舞い局面の識別基準になる。インターフェースは抽象メソッド主体なので多重継承時のメンバ名の重複はあまり問題にならない。共通の実装メソッドに集約されるからである。インターフェースは非インスタンス対象である。
- ミックスイン
- (mixin)はインターフェースに似たプログラム概念を指す用語である。機能名は言語によってトレイトまたはプロトコルと言われる。抽象&具象メソッドとデータメンバで構成される継承専用クラスを意味する。クラスを特徴付けるための装飾部品である。クラスによるトレイトの継承は実装と呼ばれる。多重実装可が普通である。インターフェースとの違いは、トレイトの実装階層に焦点が当てられている事であり、オブジェクトを所有メンバで特定してまとめることがその役割である。トレイトは自身の上位集合であるオブジェクトをグループ化できる。構造的型付けに準拠しているので所属メンバ構成自体がトレイト等価性の識別基準になる。これはトレイト実装を明記してなくても、そのトレイトが内包する全メンバを所持していれば同じトレイトと見なされることを意味する。トレイトは合成や交差が可能である。トレイトは多重継承時のメンバ名重複の際にその参照の優先順位に注意する必要がある。トレイトは非インスタンス対象である。
- ダックタイピング
- (duck typing)は特定のデータメンバ名またはメソッド名(メソッドシグニチャ)を持っているかどうかでインスタンスを分類すること。または選り分けること。実行時に判別する仕組みであり、動的型付けに分類される。選り分けられたインスタンスはその指名データメンバないし指名メソッドでのアクセス対象になる。
- メタクラス
- (metaclass)とはクラスを定義しているクラスであるが、その実態はシステム側が用意している特別なシングルトンオブジェクトと考えた方が分かりやすい。システム内のクラス定義情報をクラスに見立てて、それをインスタンス化したものである。慣例的にこれをメタクラスと呼ぶ。メタクラスはクラスのデータメンバとメソッドの定義情報を指し、それを操作する機能はリフレクションと呼ばれる。クラスベースで用いられるものである。
- リフレクション
- (reflection)はクラスの定義情報を変更する機能であるが、言語ごとに変更できる定義情報の範囲は異なっている。データメンバではデータ型、識別子、可視性が変更対象になる。メソッドではリターン型、識別子、パラメータリスト、可視性、仮想指定が変更対象になる。双方の追加定義と削除もできる事がある。スーパークラスも変更できる事がある。また、実行時の文字列(char配列やString)をデータメンバとメソッドの内部識別子として解釈できる機能もリフレクションに当たる。これは実行時の文字列によるデータメンバの参照とメソッドの呼び出しを可能にする。
- 遅延バインディング
- (late binding)は、識別子が参照するオブジェクトをコンパイル時に決める事前バインディング(early binding)の対義語であり、この場合は識別子の参照先を実行時に決める動的バインディングとほぼ同じ意味で用いられる。一方で、特にリフレクション機能を通して実装される方を遅延バインディングとする考え方もある。抽象化された型に対して、実行時の文字列(char配列やString)を内部識別子に解釈し、コンパイル時には認識されていなかったオブジェクトをローディングして代入する仕組みなどである。オブジェクトの呼び出しが、DLLやクラスライブラリの動的ローディングに繋がることが遅延バインディングと呼ばれる基準になる。また、プログラム内でデータとして扱われているコードブロックを関数の型に代入して呼び出すという仕組みがある。そのコードブロックは文字値と数値の混合配列であり、リフレクション機能を利用して実行する。
- 動的ディスパッチ
- (dynamic dispatch)はメソッドの呼び出しを受けるオブジェクトの側に焦点を当てたプログラム概念である。一般的なローカルメソッドでは、メソッド識別子にマッピングされている参照が指すメソッド実体を呼び出す仕組みを意味する。参照が指す先はプログラム実行中に随時変更されるのでコンパイル時ではなく実行時のその都度に確定されることになる。リモートメソッドでは、受け取ったバイトデータ列を解釈しリフレクション機能でメソッドを呼び出す仕組みを意味する。受信側の実行時状態による選択が加えられる事もある。始めのアクセスで所有メソッドリストを呼び出し側に送り、無駄なエラーリクエストを無くす仕組みと併用される事が多い。
- 動的バインディング
- (dynamic binding)は特定の識別子から呼び出されるメソッドないし参照されるデータメンバが、コンパイル時ではなく実行時に決められる仕組み全般を指す用語である。プロトタイプベースのオブジェクトからメソッドとデータメンバが参照される機構、仮想関数メソッドから派生クラスのメソッドが呼び出されるシングルディスパッチ機構、メソッドに渡された実引数を実行時型チェックしてその結果に従いプロセスを分岐させるシングルディスパッチ~多重ディスパッチ機構などが例である。
- オーバーロード
- (overloading)は一つのメソッド名に複数の異なるパラメータリスト(引数欄)を付けたものを列挙してメソッド名を多重定義すること。演算子もオーバーロード対象であり、単項演算子なら一つの引数の型、二項演算子なら二つの引数の型を多重定義することで演算対象の値の型ごとに計算内容をカスタマイズできる。特筆的なものにクロージャ=関数オブジェクトを表現する ( )演算子がありこれは任意個数の引数を多重定義できる。インスタンス自体を任意構成の引数とともに関数のように使える仕組みである。
- オーバーライド
- (method overriding)は継承による階層的クラス構造のインスタンスにおいて、サブクラスのメソッドシグニチャの処理内容でそのスーパークラス側の同じメソッドシグニチャの処理内容を置き換える仕組みを指す。メソッドシグニチャとは「返り値+メソッド名+引数欄」で構成される識別単位である。この指定は親側のメソッドが上書きされるのをデフォルトにするのと、子側のメソッドで上書きするのをデフォルトにする二通りがある。前者なら子側のメソッドをoverrideやredefineで修飾しそれで親側メソッドを上書きする。後者なら親側のメソッドをvirtualやdeferredやabstractで修飾しそれは子側メソッドで上書きされる。それとは別にただメソッドを上書き不可にする場合はfinalなどで修飾する。
- ジェネリクス
- (generics)はクラス内のデータメンバの型、メソッドの引数の型、返り値の型を総称化して型変数とし、任意の具体的な型を型引数にしてコンストラクタを呼び出して、型変数に型引数を当てはめて(適用)インスタンスを生成する仕組みを指す。クラス内の型の決定をコンストラクタまで先送りする手法である。このジェネリッククラスに対して、引数の型と返り値の型を総称化したジェネリック関数もある。型変数をバリアンスにすることで適用クラスの派生クラスも当てはめることができる。型変数のバリアンスを用いないジェネリクスの方は特にテンプレートと呼ばれる。
- テンプレート
- (template)は型変数のバリアンスを用いない方のジェネリクスを指す。コンパイル時にそれぞれのテンプレートクラスおよびテンプレート関数の型変数(仮型引数)部分に、それぞれの生成箇所の型引数(実型引数)を当てはめたソースコードがそのまま複製される仕組みである。
- バリアンス
- (variance)は、あるクラスで型注釈された箇所にそれと継承関係があるクラスも適用できるようにする仕組みである。注釈クラスとその派生クラスを適用できるようにしたのは共変性と呼ばれる。注釈クラスとその基底クラスを適用できるようにしたのは反変性と呼ばれる。オブジェクト指向下のバリアンスは、もっぱらジェネリクスのカテゴリで用いられジェネリッククラスの型変数が対象になる。バリアンスはジェネリッククラスの継承構造上のオーバーライドで様々に応用される。
- 型制約
- (type constraint)はジェネリッククラスの型引数ないし型変数、または代入値の型が実行時に決められる動的束縛型に用いられるものである。それぞれを指定クラスで記号修飾して、型引数と型変数では指定クラスの派生クラスのみを適用できるようにし、動的束縛型では指定クラスの派生クラス値のみが代入できるようにする仕組みである。これは型境界(type bound)とも呼ばれる。
- コンポジション
- 合成(composition)は強いhas-a関係。AクラスがBクラスをデータメンバにし、Aのコンストラクタと同時にBインスタンスが生成され、Aのデストラクタと同時にBインスタンスが破棄される場合、AはBの合成となる。Bが自身のサブクラスで交換される場合は分離とともに破棄される。
- アグリゲーション
- 集約(aggregation)は弱いhas-a関係。AクラスがBクラスをデータメンバにし、Aクラスのコンストラクタとは関係なくBインスタンスが生成され、AクラスのデストラクタでBインスタンスが破棄されず、また分離時も破棄されない場合、AはBの集約となる。Aクラスがコレクション(配列、List、Set、Map)の仕組みでBインスタンスを持つ場合も、AはBの集約となる。コレクション性を強調する場合は収容(containment)とすることもある。
- アソシエーション
- 関連(association)。AクラスがBクラスのメソッドを呼び出す場合、AはBに関連しているとなる。AはBへの誘導可能性を持つとされる(A→B)。has-a関係で保有しているインスタンスのメソッドを呼び出すという意味で関連線は合成線または集約線と重ねて引かれることが多い。
- ディペンデンシー
- 依存(dependency)。AクラスのメソッドがBクラスのインスタンスを引数または返り値にしてる場合、AはBに依存しているとなる。返り値の例として、Aのメソッドがその返り値としてBインスタンスを生成する場合も、AはBに依存しているとなる。
- デリゲーション
- 委譲(delegation)は基本例としては、呼び出されたあるクラスのメソッドが自分への引数を他のクラスの同名メソッドにそのまま渡して、その同名メソッドの返り値をそのまま呼び出し元に返すという仕組みを指す。委譲先となる他のクラスはhas-a関係で保有されているものが使われる。委譲先メソッドは必ずしも同名ではなくマッピング名の場合もあり、引数も構成を変えて渡される場合もある。