「オブジェクト指向プログラミング」の版間の差分

削除された内容 追加された内容
G000001 (会話 | 投稿記録)
RnTknn (会話) による ID:86075221 の版を取り消し 差し戻しの連鎖が続くようであれば、 Wikipedia:保護依頼 を依頼しようと思います。
タグ: 取り消し
RnTknn (会話 | 投稿記録)
では、自分が記していた明らかな間違いと冗長な文だけをどうか修正させてください。
20行目:
[[Java]]、[[C++]]、[[C_Sharp|C#]]、[[Python]]、[[R言語|R]]、[[PHP (プログラミング言語)|PHP]]、[[Visual_Basic_.NET]]、[[JavaScript]]、[[Ruby]]、[[Perl]]、[[:en:SIMSCRIPT|SIMSCRIPT(英語版)]]、[[Object Pascal]]、[[Objective-C]]、[[Dart]]、[[Swift (プログラミング言語)|Swift]]、[[Scala]]、[[Kotlin]]、[[Common Lisp]]、[[MATLAB]]、そして[[Smalltalk]]。
 
<!-- 以上まで、ほぼ [[en:Object-oriented programming]] oldid=1047374345 の翻訳 -->
 
<!-- 以下より文末までほぼ出典なしの記述(出典なしの記述が大量に続いている、ということが以前より懸念されています。詳細は議論ノートをご参照ください -->
 
<!-- 以上まで、ほぼ [[en:Object-oriented programming]] oldid=1047374345 の翻訳 --><!-- 以下より文末までほぼ出典なしの記述(出典なしの記述が大量に続いている、ということが以前より懸念されています。詳細は議論ノートをご参照ください -->
== 歴史 ==
{{独自研究|date=2021-10}}
 
'''[[オブジェクト指向]]'''という言葉自体は、計算機科学者[[アラン・ケイ]]によって作り出されている。[[Simula]]言語などにインスパイアされたケイが1967年頃に口にしたと伝えられるこの造語は<ref name="造語">“At Utah sometime after Nov 66 when, 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. It was probably in 1967 when someone asked me what I was doing, and I said: "It's object-oriented programming".”[http://www.purl.org/stefan_ram/pub/doc_kay_oop_en%7CDr. Alan Kay on the Meaning of “Object-Oriented Programming”]</ref>、彼が1972年から開発を始めた言語[[Smalltalk]]の設計を説明する過程で明確な用語として発信され、1981年頃から知名度を得るようになった。80年代半ばになるとオブジェクト指向の解釈は、元々のアラン・ケイによる[[Smalltalk]]の様式と、1983年に計算機科学者[[ビャーネ・ストロヴストルップ]]が公開した[[C++]]の様式に二分された。前者では[[メッセージング]]という概念が基礎にされ、後者では[[Simula|Simula67]]由来の諸機能を加えた[[抽象データ型]]のスーパーセットが基礎にされていた。現在ではC++の様式がオブジェクト指向の標準になっている。
 
=== Simula以前 ===
 
1954年に初の[[高水準言語]]・[[FORTRAN]]が登場すると、開発効率の劇的な向上と共にソフトウェア要求度も自然と高まりを見せてプログラム規模の急速な拡大が始まった。それに対応するために肥大化したメインルーチンを[[サブルーチン]]に分割する手法と、[[スパゲティプログラム|スパゲティ化]]した[[Goto文|goto命令]]を[[制御構造|制御フロー構文]]に置き換える手法が編み出され、これらは1960年に公開された言語「[[ALGOL|ALGOL60]]」で形式化された。当時のALGOLは[[アルゴリズム]]記述の一つの模範形と見なされたが、それと並行して北欧を中心にした計算機科学者たちはより大局的な観点によるプログラム開発技法の研究を進めていた。
 
=== Simulaの開発(1962 - 72) ===
49 ⟶ 43行目:
[[Simula]]を研究対象にしていた[[ベル研究所|AT&Tベル研究所]]の計算機科学者[[ビャーネ・ストロヴストルップ]]は、1979年からクラス付きC言語の制作に取り組み、1983年に「[[C++]]」を公開した。C++で実装された[[クラス (コンピュータ)|クラス]]は、Simula由来の[[継承 (プログラミング)|継承]]と仮想関数に加えて、段階的な[[レキシカルスコープ]]の概念をクラス構造に応用した[[アクセスコントロール]]を備えていた。C++で確立されたアクセスコントロールは情報隠蔽によるデータ抽象を提示したが、コードスタイル上ほとんどザル化されており、その理由からストロヴストルップ自身もC++は正しくない(''not just'')オブジェクト指向言語であると明言している。1986年にソフトウェア技術者[[バートランド・メイヤー]]が制作した「[[Eiffel]]」の方は、正しいオブジェクト指向を標榜してクラスのデータ抽象を遵守させるコードスタイルが導入されていた。クラスメンバ(フィーチャー)は属性/手続き/関数の三種構成で、手続きで属性を変更して関数で属性を閲覧するという形式に限定されており、これは[[抽象データ型]]に忠実な実装であった。アクセスコントロールはC++のとは異なるクラス指名方式にされ、仮想関数機能は延期手続き/関数として実装された。
 
1986年から[[Association for Computing Machinery|ACM]]が[[OOPSLA]]を年度開催するようになり、オブジェクト指向は従来の[[構造化プログラミング|構造化開発]]に代わる技術として明確に意識され始めた。OOPSLAのプログラミング言語セクションでは、[[抽象データ型]]を基礎にした[[クラス (コンピュータ)|クラス]]・パラダイムが主要テーマにされ、それを標準化するための数々のトピックが議題に上げられている。[[モジュール|モジュール分割]]、[[抽象化 (計算機科学)|抽象化]]、[[再利用|再利用性]]、[[継承 (プログラミング)|階層構造]]、複合構成、情報隠蔽、実行時多態、[[動的束縛]]、[[総称型]]、[[永続性]]、[[並行性]]、[[ガベージコレクション|自動メモリ管理]]といったものがそうであり、参画した識者たちによる寄稿、出版、講演を通して世間にも広められた。そうした潮流の中で[[ビャーネ・ストロヴストルップ|ストロヴストルップ]]はデータ抽象の重要性を訴え、[[バーバラ・リスコフ|リスコフ]]は[[上位概念、下位概念、同位概念および同一概念|基底と派生]]に分けたデータ抽象の階層構造の連結関係([[リスコフの置換原則|置換原則]])について提言した。[[契約による設計]]と[[開放/閉鎖原則|開放閉鎖原則]]を提唱する[[バートランド・メイヤー|メイヤー]]が1988年に刊行した『オブジェクト指向ソフトウェア構築』によるEiffel式のクラス理論は高く評価され、Eiffelを現行の模範形とする声も多く上がった。ただしこれは学術寄りの意見でもあったようで、世間のプログラマの間では厳格なEiffelよりも、柔軟で融通の利くC++の人気の方が高まっていた。他方で[[アラン・ケイ]]のメッセージ・メタファに忠実であろうとする動きもあり、1984年に制作された「[[Objective-C]]」はC言語をSmalltalk方向に拡張してメッセージ式を平易化した言語であった。1987年に[[パロアルト研究所]]で誕生した「[[Self]]」は、Smalltalkの[[クラスベース]]設計をより柔軟に平易化した[[プロトタイプベース]]を編み出している。これらのメッセージレシーバーは、静的メソッド選択優先の動的ディスパッチ機構という方式でほぼ形式化された。メッセージレシーバーの仕組みは[[遠隔手続き呼出し]]や[[Object Request Broker|オブジェクト要求ブローカー]]の実装に適していたので、[[分散システム]]とオブジェクト指向の親和性を認識させることになった
 
=== コンポーネントとネットワーク(1989 - 97) ===
63 ⟶ 57行目:
** [[Smalltalk]]様式 - クラスとインスタンスの[[相対性]]を付与してオブジェクトを体系化している。動的型付け中心。[[メッセージパッシング]]による多態性。
** [[C++]]様式 - クラス(型)とインスタンス(値)<!--型付け値 ←怪しい用語-->に分離してオブジェクトを体系化している。{{仮リンク|動的ディスパッチ|en|Dynamic dispatch}}による多態性。
*** [[静的型付け]] - 実行時のオブジェラストの構成が基本的解釈(型チェックなど)を主にコンパイル時固定されている。
*** [[動的型付け]] - 実行時のオブジェラストの構成の変更が前提解釈(型チェックなど)を主に実行時されている。{{疑問点|date=2021年10月|title=動的型付けはそういう意味ではない}}
* [[プロトタイプベース]] - オブジェクトのクローンでオブジェクトを構築する。クラスとインスタンスの[[相対性]]をオブジェクトから撤廃して、プロトタイプでオブジェクトを体系化している。動的型付け中心。[[動的束縛|動的バインディング]]による多態性。
 
本稿では最も標準的なクラスベースのC++様式の静的型付けを基準にして説明する。<!-- 動的型付けのオブジェクト指向言語もかなり使われているので疑問。 -->なお、場合によっては C言語などオブジェクト指向を支援しない言語でオブジェクト指向的なプログラミングが行われることもある<!-- それについての書籍があったはず -->。
 
なお、場合によっては C言語などオブジェクト指向を支援しない言語でオブジェクト指向的なプログラミングが行われることもある<!-- それについての書籍があったはず -->。
 
参考: <!-- [[クラスベース]]OOPの中心である[[クラス (コンピュータ)|クラス]]の実装様式を規定している以下の三項目は、 「クラスの実装様式」では意味がはっきりしない。-->
76 ⟶ 68行目:
 
=== クラスとインスタンス ===
OOPの要点である[[クラス (コンピュータ)|クラス]]は、[[データ構造]]とそれを扱うための操作・振る舞いをひとまとめにした一種の[[モジュール|プログラムモジュール]]機能として定義されており、その実装は[[Simula|Simula67]]由来の[[継承 (プログラミング)|継承]]と動的ディスパッチを加えた[[抽象データ型]]のスーパーセットにされていることが多い。クラスのデータ構造は[[レコード型]]や[[構造体]]に似た書式で定義されることが多く、データ構造の要素は言語ごとに[[フィールド (計算機科学)|フィールド]]、[[プロパティ (プログラミング)|プロパティ]]、[[属性]]、メンバ変数などと呼ばれている。クラスに定義される操作・振る舞いは[[メソッド (計算機科学)|メソッド]]やメンバ[[関数 (プログラミング)|関数]]などと呼ばれる。メソッドと{{要説明|date=2021年10月|title=クラス、特定 (オブジェクト対象に所属させることを前提にして[[This)分類 (プログラミング)|This参照]]を多相シンボルにしたディスパッチコードしての[[関数 (プログラミング)|関数]]/[[手続き]]を意味してう話があべき}}
 
{{要説明|date=2021年10月|title=クラスは (オブジェクトの)分類 という話があるべき。}}
 
OOP言語の[[クラス (コンピュータ)|クラス]]と、そうでない言語での[[モジュール]]の違いを知ることは、OOPを理解する上でも重要になる。どちらも[[プロシージャ|手続き]]と[[データ]]の複合体であるが、クラスの第一の特徴はそれに[[継承 (プログラミング)|継承]]が備えられていることであり、次に[[This (プログラミング)|This参照]]の機構と、[[継承 (プログラミング)|継承]]構造上の[[内包と外延|内包]]的な{{仮リンク|動的ディスパッチ|en|Dynamic dispatch}}である。その次になる{{仮リンク|情報隠蔽|en|information hiding}}と、定義と実装に分離しての[[抽象化 (計算機科学)|抽象化]]の機構は、OOP以前の{{仮リンク|モジュラルプログラミング|en|Modular programming}}からのものである。振る舞い抽象を担っている[[インタフェース (抽象型)|インターフェース]]の概念もそちらが先例であったが、データ抽象を担っている[[カプセル化]](情報隠蔽とThis参照の融合)の採用はOOPが最初である。[[継承 (プログラミング)|継承]]構造上の内包的な動的ディスパッチによる[[派生型|サブタイピング]](=[[ポリモーフィズム]])はOOP発祥であるが、それを純粋化すると前述の[[インタフェース (抽象型)|インターフェース]]になる。OOP以前の[[構造化分析設計技法|構造化開発]]のモジュールには情報隠蔽はあるが、[[継承 (プログラミング)|継承]]はなく、[[カプセル化]]や[[ポリモーフィズム]]といった抽象化の諸機構も持たない。なお、{{仮リンク|振る舞いサブタイピング|en|Behavioral subtyping}}は[[多重ディスパッチ]]のOOPでは軽視されており、カプセル化は[[動的型付け]]のOOPではしばしば軽視されている。従ってクラスを特徴付けている要素とは即ち[[継承 (プログラミング)|継承]]であり{{疑問点|date=2021年10月}}、継承はプログラムの再利用性と保守性を高めるためのメカニズムと定義されている。
 
C++様式のクラスベースは[[オブジェクト (プログラミング)|オブジェクト]]を、[[型理論]]に沿った[[型システム|型]](type)と[[型付け|型付け]]{{疑問点|date=2021年10月|title=怪しい用語}}(term)に分離している。その型の一種であるユーザー定義型(user defined type)がクラスにされており、そのクラスで[[型付け]]された値が[[インスタンス]]になっている。ユーザー定義型とは[[構造体]]と同じものに似たデータ複合体であり{{疑問点|date=2021年10月}}、OOPでは[[手続き]](のポインタ)も構造体そのメンバにされている。<!-- ユーザー定義型は[[オブジェクト型]]と呼ばれることもあるが、このオブジェクト型と後節の「[[オブジェクト (プログラミング)|オブジェクト]]」の意味上の繋がりはない。←怪しいし中途半端。今の状態ならない方がマシでしょう。-->[[クラス (コンピュータ)|クラス]]はインスタンスのひな型であり、[[インスタンス]]はクラスを実体化したものである。実体化=インスタンス化とは対象クラスの全変数内容を決定し、{{疑問点範囲|[[ヒープ領域]]の基底アドレス([[This (プログラミング)|This]])を定めた上でそこにメモリ展開するという作業|date=2021年10月|title=これだと処理系による実装のような話であり、書くとしても 典型的な実装の形態 といった言い方にしないとまずい。言語のセマンティクスとしてはもっと抽象的なモデルもありうる。 ヒープとも限らないし。「メモリを確保」ならまだわかる。}}を指している。コンパイル時にその構成が確定型チェックされるユーザー定義型は[[静的型付け]]であり、実行時にもその構成を変更でき型チェックされるユーザー定義型は[[動的型付け]]である。なお、Smalltalk様式のクラスベースは[[型理論]]の[[依存型]]に似ている。依存型は型と値の境界がない型付けである。
 
=== オブジェクトとは ===
[[クラスベース]]言語での「[[オブジェクト (プログラミング)|オブジェクト]]」は、[[インスタンス]]を指す用語として説明されているが、このような重複語になった背景にはOOP原点の[[Smalltalk]]の設計がある。Smalltalkは、全てのプログラム要素は[[オブジェクト (プログラミング)|オブジェクト]]であり、全てのオブジェクトはクラスのインスタンス化であり、クラスもまたオブジェクトであり、オブジェクトは他のオブジェクトと相互作用(interaction)すると定義していた。そこでは[[クラス (コンピュータ)|クラス]]もまた[[メタクラス]](型)の[[インスタンス]]化(型付け値)になり、そのメタクラスもまた他のメタクラスのインスタンス化になっていたので、[[クラス (コンピュータ)|クラス]]と[[インスタンス]]は即ちオブジェクトの性質([[相対性]])を指すための言葉になっていた。これが[[C++]]様式では簡素化されて、クラスとインスタンスは[[型システム|型]]と[[型付け|型付け値]]の役割に固定され、メタクラスは[[リフレクション (情報工学)|リフレクション]]機能に固定されたので、クラスとインスタンス化の[[相互再帰]]が失われたオブジェクトは、相互作用できるインスタンスを指しているままで放置された。相互作用とは各種演算と同義であり、Smalltalkのクラスは相互作用できる型付け値でもあるのでオブジェクトであるが、C++様式のクラスはただの型なので演算対象に出来ないことからオブジェクトではなくなっている。
 
Smalltalk方言の[[Self]]を原点とする[[プロトタイプベース]]は、オブジェクトからクラスとインスタンスの[[相対性]]を無くしたスタイルである。数値・文字列・配列・関数・シンボル・[[構造体]]([[オブジェクト型]])といった[[プリミティブ型|基本的な型]]は備えられているが、これはオブジェクト種類の区別に特化されたものなので、[[型理論]]に沿ったクラスベースの[[型システム|それ]]とは厳密には異なっている。クラス性質を除去したオブジェクトは事実上のインスタンスに一元化されており、その全てが相互作用(interaction)する。オブジェクトの表現はスロット(シンボルとコンテンツのペアデータ)の[[可変長配列]]でなされており、オブジェクトの識別は専ら[[ダックタイピング]]によってなされる。クラス概念が無いのでサブクラス化とインスタンス化は成立せず、代わりにクローン(複製)によってオブジェクトの継承がなされており、クローンはインスタンス化の代替になる。複製元オブジェクトは、複製先オブジェクトのプロトタイプと呼ばれる。
93 ⟶ 83行目:
データ構造とそれを扱うためのメソッド群を情報隠蔽の概念と合わせてモジュール化(パッケージ化)するという手法が[[カプセル化]]と呼ばれる。カプセル化されたメソッドは、[[This (プログラミング)|This値]]が暗黙の先頭引数として常に渡されるように実装される。This値とはクラスのデータ構造をメモリ展開するための[[ヒープ領域]]の基底アドレスを指しており、インスタンス化時に確定されたThis値によってメソッドは専用のデータ構造にアクセスできる。専用メソッドを通してのデータ構造の閲覧と変更は、[[抽象データ型]]の考え方に沿ったデータ構造の抽象化を意味することになり、これは{{仮リンク|Data Abstraction|en|Abstraction (computer science)|label=データ抽象}}と呼ばれる。データ閲覧用メソッドはゲッター/アクセッサと呼ばれ、データ変更用メソッドはセッター/ミューテイタと呼ばれる。
 
{{仮リンク|情報隠蔽|en|information hiding}}とはそのクラスのデータ構造の各要素および各メソッドを必要に応じて内部隠蔽するという概念である。内部隠蔽されたデータ要素とメソッドはそのクラス外部からのアクセスが禁止される。[[抽象データ型]]本来の形式ではデータ構造のみが隠蔽対象になるので、これはデータ隠蔽とも呼ばれる。隠蔽指定外のデータ要素とメソッドは外部公開されて、そのクラス外部からもアクセス可能になる。外部公開の範囲を指定する機能は[[アクセスコントロール]]と呼ばれており、これが内部隠蔽の仕組みを担っている。クラスの[[レキシカルスコープ]]を基準にした段階的なアクセス許可範囲は可視性と呼ばれる。可視性は無制限・任意クラスグループ限定・派生クラスグループ限定・自クラス限定(内部隠蔽)の四段階が[[統一モデリング言語|UML]][[クラス図]]では標準にされている。
 
=== [[継承 (プログラミング)|継承]] ===
既存クラスのデータ/メソッド構成に、任意のデータ/メソッド構成を付け足して、既存構成+新規構成の新しいクラスを定義するという手法が[[継承 (プログラミング)|継承]]と呼ばれる。また、各クラスの共通構成パートを括りだして特有構成パートと分離することでオブジェクトを分類体系化し、同時にその共通構成パートの記号化によってソースコード内の重複記述を削減する機能とも解釈される。これは差分プログラミング目的の継承であり、1990年代までは多用さ実装継承(implementation inheritance)とも呼ばれた。
 
[[リスコフの置換原則|リスコフ置換原則]]と[[開放/閉鎖原則]]が取り上げられると、既存構成に抽象メソッドを置いて新規構成にその実装メソッドを置くという[[オーバーライド|メソッドオーバーライド]]を用いるための{{仮リンク|振る舞いサブタイピング|en|Behavioral subtyping}}目的の継承の方が重視されるようになり、これは界面継承(interface inheritance)とも呼ばれた。メソッド定義の引き継ぎと[[サブタイプ|サブタイピング]]を中心にした[[Is-a]]関係主体の継承をUML[[クラス図]]は特化(specialization)と定義している。
既存クラスはスーパークラス・親クラス・基底クラスなどと呼ばれ、新しいクラスはサブクラス・子クラス・派生クラスなどと呼ばれる。親と子は差分プログラミング重視で、基底と派生はサブタイピング重視で用いられる。継承できるクラスが一つに限られている単一継承を採用している言語と、継承できるクラスの数に制限がない多重継承を採用している言語がある。<!-- 概念的に インターフェース継承(型継承、[[is-a関係]]、下位分類)と 実装の継承 の2つの側面があるといったことを書いた方がよさそう。 記述によっては両方の継承関係が同時に生じる。 -->抽象メソッドを持つクラスは抽象クラスと呼ばれる。基底クラス側でリターン型とパラメータのみが定義されて実行コードブロックが未定義のままの抽象メソッドは、その派生クラス側の実装メソッドで[[オーバーライド]]される。オーバーライドは遅延結合による多相な[[複雑系]][[アルゴリズム]]を表現するオープン[[再帰]](open recursion)のメカニズムにもなっている。
 
既存クラスはスーパークラス・親クラス・基底クラスなどと呼ばれ、新しいクラスはサブクラス・子クラス・派生クラスなどと呼ばれる。親と子は差分プログラミング重視で、基底と派生はサブタイピング重視で用いられる。継承できるクラスが一つに限られている単一継承を採用している言語と、継承できるクラスの数に制限がない多重継承を採用している言語がある。<!-- 概念的に インターフェース継承(型継承、[[is-a関係]]、下位分類)と 実装の継承 の2つの側面があるといったことを書いた方がよさそう。 記述によっては両方の継承関係が同時に生じる。 -->抽象メソッドを持つクラスは抽象クラスと呼ばれる。基底クラス側でリターン型とパラメータのみが定義されて実行コードブロックが未定義のままの抽象メソッドは、その派生クラス側の実装メソッドで[[オーバーライド]]される。オーバーライドは遅延結合による多相な[[複雑系]][[アルゴリズム]]を表現するオープン[[再帰]](open recursion)のメカニズムにもなっている。
抽象メソッドのみで構成される純粋抽象クラスは[[インタフェース (抽象型)|インターフェース]]と呼ばれ、その継承をUML[[クラス図]]は実装(implementation)と定義している。インターフェースの実装は、サブタイピングの[[Is-a]]関係を完全順守させるメカニズムである。{{仮リンク|モジュラルプログラミング|en|Modular programming}}が先例になる実装は、[[継承 (プログラミング)|継承]]から[[派生型|派生]]への回帰と言えるものである。
 
抽象メソッドのみで構成される純粋抽象クラスは[[インタフェース (抽象型)|インターフェース]]と呼ばれ、その継承をUML[[クラス図]]は実装(implementation)と定義している。インターフェースの実装は、[[サブタイプ|サブタイピング]]の[[Is-a]]関係を完全順守させるメカニズムである。また、クラスへの機能注入を目的にして、主に具象メソッドをクラスに注入す継承させるという継承アプローチもあり、これは[[ミックスイン]](mix-in)と呼ばれる。mix-in具象メソッド集合体は[[トレイト]]の形態にされることが多い。トレイトmix-inUML[[抽象メソッドクラス図]]も持では扱われいない継承関係である。
 
=== [[ポリモーフィズム]] ===