「プロトタイプベース」の版間の差分
m 少なくともCLOS(Common Lisp)とDylanはプロトタイプ指向ではありませんので、一覧から削除しました。 |
HDK13-2200 (会話 | 投稿記録) m 誤字修正。 |
||
(6人の利用者による、間の32版が非表示) | |||
1行目: | 1行目: | ||
{{出典の明記|date=2015年12月}} |
{{出典の明記|date=2015年12月}} |
||
[[ファイル:Smalltalk-metaclass-sample.svg|境界|右|フレームなし|248x248ピクセル]] |
|||
⚫ | |||
'''プロトタイプベース''' ({{lang-en-short| |
'''プロトタイプベース''' ({{lang-en-short|Prototype-based}}) は、[[オブジェクト指向プログラミング]](OOP)のスタイルのひとつであり、[[オブジェクト (プログラミング)|オブジェクト]]の生成に既存[[オブジェクト (プログラミング)|オブジェクト]]の複製を用いるスタイルを指している。これには直後にメンバを拡充するための空オブジェクトの複製も含まれている。このスタイルは、インスタンスベース(Instance-based)とも呼ばれている。これと対比されるOOPスタイルに[[クラスベース]]がある。 |
||
プロトタイプベースOOPの原点は[[Smalltalk]]方言の[[Self]]であり、Smalltalkのクラスベース設計を平易化する試みから1987年に誕生している。他には[[Lua]]、[[JavaScript]]、[[Etoys]]、[[ECMAScript]]、[[REBOL]]、[[Io (プログラミング言語)|Io]]、[[TypeScript]]などがある。 |
|||
メタオブジェクト(''metaobject'')は「[[LISP]]」由来のプログラム概念であり、実装的には[[変数 (プログラミング)|変数]]と[[関数 (プログラミング)|関数]]双方の[[識別子|識別名]]と[[参照 (情報工学)|参照値]]をペア定義できる可変サイズの[[構造体|データ構造体]]であることが多い。[[委譲]]先となる別のメタオブジェクトの識別名と参照値もペア定義できる。メタオブジェクトはフレーム&スロット(''frame&slot'')の機構名で読み替えられてもいる。プログラミング言語仕様上ではプロトタイプ(''prototype'')の機能名で実装されていることが多い。クラスの機能名で実装している言語もあるのでこの場合は誤解を招きやすくなっている。プロトタイプを複製して[[インスタンス]]が生成される。インスタンスはオブジェクトとも呼ばれる。プロトタイプは動的にカスタマイズできる「[[型システム|型]]」と見なせるものであり、その型を複製=量化したインスタンスは自由に加工/計算/代入できる「[[値 (情報工学)|値]]」になる。 |
|||
プロトタイプとは、複製元になった[[オブジェクト (プログラミング)|オブジェクト]]を意味しており、複製先のオブジェクトから見てそう呼ばれる。プロトタイプは同時にそのオブジェクトの暗黙の[[委譲]]先になり、これはプロトタイプを複製が[[継承 (プログラミング)|継承]]していることと同じになる。 |
|||
⚫ | |||
⚫ | |||
=== メタオブジェクト === |
|||
プロトタイプベースは、[[Smalltalk]]の[[クラスベース]]設計を平易化する試みから考案されたスタイルなので、Smalltalkの設計を知らないとそれが作られた理由も分からないものになる。ここでは[[アラン・ケイ]]が概略したSmalltalk設計の六項目を紹介して、クラスベースに関連する部分を和訳しておく<ref name="EarlyHistoryOfSmalltalk">{{Cite web|url=http://worrydream.com/EarlyHistoryOfSmalltalk/|title=The Early History Of Smalltalk|accessdate=2019-01|publisher=}}</ref>。{{Quotation|1, EverythingIsAnObject.(全てはオブジェクトである) |
|||
{{Quotation|あなたはプロトタイプを作り、新しいインスタンスを作る。双方のオブジェクトは変幻自在だ。新しいフィールドとメソッドを付け足して拡充できる。その行為はプロトタイプと同等である。類似オブジェクトを作るためのクラスとその継承も必要ない。これ以上のオブジェクト指向があるだろうか?|Douglas Crockford(JavaScript developer)}}標準的なメタオブジェクトは「フレーム&スロット」「シンボル」「データ」「コード」の四要素から構成される。この四要素はいずれもオブジェクトである。データは変数値/定数値を指す。コードは引数有り/無し関数式を指す。シンボルはいわゆる識別子であり、データが束縛されたら変数名になり、またコードが束縛されたら関数名になる。フレーム&スロットはシンボル(変数名/関数名)が集約される媒体であり、プロトタイプ/インスタンスを指す。プロトタイプは所有シンボル先の要self変数に値を代入できず、また所有シンボル先の要self関数を呼び出せないオブジェクトである。インスタンスはそれらが可能なオブジェクトである。要self変数/関数はインスタンス変数/関数であり、そうでないものはクラス変数/関数である。インスタンスはプロトタイプを複製する方式で生成される。プロトタイプとインスタンスは共にそのメンバとなる変数と関数を自由に付け足すことができる。上述のメカニズムから変数と関数もオブジェクト(フレーム&スロット)になるので、変数にそのメンバ変数/メンバ関数を持たせることも可能であり、関数ではそのローカル変数/ローカル関数が、メンバ変数/メンバ関数として解釈される。シンボルはオブジェクトを識別するための用途にほぼ限られているが、仕組み上はそれにもメンバを付けることができる。シンボルは上述の四要素とプロトタイプ/インスタンスを分類するためのメタ情報IDとしても使われる。また後述のセレクタ(振る舞い指示子)としても使われる。 |
|||
2, Objects communicate by sending and receiving messages (in terms of objects). |
|||
フレーム&スロット、変数値、関数式、関数の引数値、関数の返り値は、それぞれがお互いをメンバにできるので、入れ子の連結関係で所有ないし所属し合えるようになっている。変数値にメンバ変数/メンバ関数を付けると、[[クラスベース]][[オブジェクト指向プログラミング|OOP]]の[[インスタンス]]と同等になる。void関数は専用の書式でクラスベースOOPのインスタンスと同等になり、そのvoid関数内のローカル変数/ローカル関数がメンバ変数/メンバ関数になる。メンバ変数付き関数とメンバ関数付き変数は、[[関数オブジェクト]]または[[クロージャ]]と同等なものである。 |
|||
3, Objects have their own memory (in terms of objects).(オブジェクトは自身の記憶を持つ) |
|||
=== デリゲーション === |
|||
オブジェクトのメンバ関係の連鎖メカニズムは、デリゲーション([[委譲]])によるオブジェクトのコミュニケーションを活性化させる。これにはセレクタ(振る舞い指示子)を用いる言語もあるが、大抵はコールするその関数オブジェクト名またはそのメソッド名が振る舞い指示子と同義になっている。関数オブジェクトが引数とともにコールされてそこで指定処理に対応できない場合は、そのメンバ関数またはメンバ変数のメッセージレシーバーに引数を渡してそちらに委譲する。委譲先でも不可だった場合はそのまた次のメンバにたらい回しもできる。オブジェクトはそのたらい回しの結果返ってきた値を自身の返り値にできる。 |
|||
4, Every object is an instance of a class (which must be an object).(全てのオブジェクトはクラスのインスタンスであり、クラスもまたオブジェクトである) |
|||
=== ダックタイピング === |
|||
5, The class holds the shared behavior for its instances (in the form of objects in a program list).(クラスはそのインスタンスたちが共有する振る舞いを保持する) |
|||
=== カプセル化/継承/多態性 === |
|||
6, To eval a program list, control is passed to the first object and the remainder is treated as its message.}}(4)は[[数学的帰納法|数学的帰納]]な文章なので、[[インスタンス]]のひな型である[[クラス (コンピュータ)|クラス]]もまた[[メタクラス]]のインスタンス化であり、そのメタクラスもまた他のメタクラスのインスタンス化であると解釈される。これは元祖[[クラスベース]]の大きな特徴であったが、実際はもう少し複雑でメタクラスとクラスの間に中間媒体が挟まれていた。i=インスタンス/C=クラス/M=メタクラスとするとインスタンス化の流れは、M → C class → C → iとなり、C classが中間媒体である。中間媒体は不変の[[静的型付け]]用としてオリジナルを保存し、クラスは可変の[[動的型付け]]用であった。 |
|||
=== 関数型的側面 === |
|||
また、(3)で記憶(データ)はクラスとインスタンスの双方が持つが、(5)で振る舞い(メソッド)はクラスのみが保持するとされており、これも混乱を招きやすいネックになっていた。元祖クラスベース設計は理論面では美しかったが、実践面では甚だ複雑として開発陣からも不評になり、それは哲学的なインスタンス化チェーンと、クラスとインスタンスに対する振る舞いの妙に起因していた。 |
|||
⚫ | |||
メタオブジェクトを基礎にしたプロトタイプベースは、さながら原生動物のようなプログラミングパラダイムであり、手続き型、関数型、クラスベースOOPといった様々な形態で取り扱うことができる。 |
|||
その改善策としての、オブジェクトから[[クラス (コンピュータ)|クラス]]と[[インスタンス]]の概念を無くしてしまおうという案が、プロトタイプベースの原点になっている。この案は言語視点では、クラスを無くしてインスタンスに一元化するとも解釈できるので、インスタンスベース(Instance-based)と別称された。クラスのインスタンス化を、インスタンスのクローンに置き換えることでSmalltalkクラス設計の改善が図られ、[[Self]]はこの案に沿って制作されたSmalltalk方言であった。ここでは(1)の遵守が第一にされていた。 |
|||
== 来歴 == |
|||
なお、[[C++]]/[[Python]]からの静的/動的クラスベース設計では、[[クラス (コンピュータ)|クラス]]と[[インスタンス]]を、型と値の役割に固定してインスタンス化の相互再帰を無くしたことから、インスタンスのみがオブジェクトになっている。[[メタクラス]]はクラス構成操作の[[リフレクション (情報工学)|リフレクション]]機能になっている。これは(1)の事実上の撤廃であった。 |
|||
現在では、C++/Python発のクラスベース設計が多くの言語で採用されており、[[Self]]発のプロトタイプベースは少数派になっている。のみならずプロトタイプベースの代表格[[JavaScript]]、[[ECMAScript]]ではクラスベース構文が導入されるに到っており、[[TypeScript]]はクラスベースとプロトタイプベースの折衷にされている。プロトタイプベースはやや汎用性に欠けてオブジェクト指向の主流にはなり得なかったという結論になる。 |
|||
⚫ | |||
[[Self]]とは少し別の切り口から、[[Smalltalk]][[クラスベース]]設計の平易化を図った{{仮リンク|ダグラス・クロックフォード|en|Douglas Crockford}}は、[[JavaScript]]のプロトタイプベースをこのように概略している<ref>{{cite web|last=Crockford|first=Douglas|title=Prototypal Inheritance in JavaScript|url=http://crockford.com/javascript/prototypal.html|access-date=22 June 2021}}</ref>。{{Quotation|You make prototype objects, and then … make new instances. Objects are mutable in JavaScript, so we can augment the new instances, giving them new fields and methods. These can then act as prototypes for even newer objects. We don't need classes to make lots of similar objects… Objects inherit from objects. What could be more object oriented than that?<br/>(あなたはプロトタイプ・オブジェクトと新しいインスタンスを作る。オブジェクトは可変であり、新フィールドと新メソッドを加えて拡充できる。これもまた新生オブジェクトのプロトタイプになる。クラスは必要ない。オブジェクトも同様に継承できるからだ。これ以上のオブジェクト指向があるだろうか?)}}プロトタイプベースはプログラマに、オブジェクトをどう振る舞わせるかということのみに集中させて、オブジェクトが実際に振る舞えるかどうかの疑問を後回しにできる環境を提供する<ref>{{Cite journal|last=Taivalsaari|first=Antero|last2=Noble|first2=James|date=1998|title=Thinking with prototypes|url=https://doi.org/10.1145/346852.346949|journal=Addendum to the 1998 proceedings of the conference on Object-oriented programming, systems, languages, and applications (Addendum) - OOPSLA '98 Addendum|publisher=ACM Press|location=New York, New York, USA|doi=10.1145/346852.346949}}</ref>。振る舞いとは[[メソッド (計算機科学)|メソッド]]である。疑問の後回しとは[[動的型付け]]の[[ダックタイピング]]を意味している。プロトタイプベースは[[静的型付け]]の実装を排除してる訳ではないが、その特性と利点を最大限に活かすための[[動的型付け]]が好まれている。 |
|||
プロトタイプベースのオブジェクトは総じて、スロットの[[可変長配列]]として実装されている。スロットとは「シンボル+コンテンツ」のペアデータである。シンボルは[[プロパティ (プログラミング)|プロパティ]]名や[[メソッド (計算機科学)|メソッド]]名を表わし、コンテンツはプロパティ値や[[コードブロック]]参照を表わす。プロパティスロットはプロトタイプ参照や[[This (プログラミング)|this]]参照(self参照)の容器にもなる。[[Self]]ではメソッドスロットがメッセージ式で送られるセレクタの受け手になる。 |
|||
オブジェクトの構築は、クローン方式かエクスニヒロ方式で行われる。クローン(clone)は既存オブジェクトを複製する方式であり、複製後にプロパティ/メソッドの自由な取り付け取り外しもできる。エクスニヒロ(ex nihilo)はプロパティ無しメソッド無しの空オブジェクトを生成(または複製)する方式であり、生成後にプロパティ/メソッドの自由な取り付けができる。[[構造体]]に似た書式でプロパティ/メソッドを初期設定して生成する方式もエクスニヒロに分類されている。[[クラス (コンピュータ)|クラス]]概念がないのでテンプレート処理的なオブジェクト構築は不可であるが、[[クラスベース]]構文が導入された言語では代替的に可能にされており、それはエクスニヒロの方で解釈されている。 |
|||
クローンで構築されたオブジェクトのプロトタイプ-スロットには、クローン元になったオブジェクトの参照が自動代入される。プロトタイプ-スロットは再代入可能なので、エクスニヒロで構築された空オブジェクトにも、そのプロトタイプにするオブジェクト参照を自由に追加できた。プロトタイプは暗黙の[[委譲]]先になり、オブジェクトがアクセス要求されたプロパティ/メソッドを持っていない場合は、そのプロトタイプで自動サーチされる。これは[[継承 (プログラミング)|継承]]になった。 |
|||
プロトタイプベースの[[ポリモーフィズム]]は、[[クラス (コンピュータ)|クラス]]がないことから[[オーバーライド|メソッドオーバーライド]]による[[仮想関数テーブル|仮想関数]]は成立しないが、オブジェクトの{{仮リンク|構造的型付け|en|Structural type system}}解釈による[[メソッド (計算機科学)|メソッド]]の[[サブタイピング]]がそれを担っている。また、[[動的型付け]]による[[動的束縛|動的バインディング]]も用いられる。 |
|||
プロトタイプベースでは、[[カプセル化]]は軽視されていることが多い。 |
|||
== 脚注 == |
== 脚注 == |
||
{{Reflist}} |
{{Reflist}} |
||
== 参考文献 == |
|||
* {{cite book|first=Martin|last=Abadi|author-link=Martin Abadi|author2=Luca Cardelli|author2-link=Luca Cardelli|title=A Theory of Objects|publisher=Springer-Verlag|year=1996|isbn=978-1-4612-6445-3}} |
|||
* [http://www.laputan.org/reflection/warfare.html Class Warfare: Classes vs. Prototypes], by Brian Foote. |
|||
* {{cite book|editor1-last=Noble|editor1-first=James|editor2-last=Taivalsaari|editor2-first=Antero |editor3-last=Moore|editor3-first=Ivan|year=1999|title=Prototype-Based Programming: Concepts, Languages and Applications|publisher=Springer-Verlag|isbn=981-4021-25-3}} |
|||
* [http://web.media.mit.edu/~lieber/Lieberary/OOP/Delegation/Delegation.html Using Prototypical Objects to Implement Shared Behavior in Object Oriented Systems], by Henry Lieberman, 1986. |
|||
== 関連項目 == |
== 関連項目 == |
||
*[[Self]] |
*[[Self]] |
||
*[[ |
*[[Lua]] |
||
*[[JavaScript]] |
*[[JavaScript]] |
||
⚫ | |||
*[[REBOL]] |
|||
{{プログラミング言語の関連項目}} |
{{プログラミング言語の関連項目}} |
||
{{DEFAULTSORT:ふろとたいふへえす}} |
{{DEFAULTSORT:ふろとたいふへえす}} |
||
[[Category:オブジェクト指向]] |
[[Category:オブジェクト指向]] |
||
{{Computer-stub}} |
2022年10月23日 (日) 06:19時点における最新版
プロトタイプベース (英: Prototype-based) は、オブジェクト指向プログラミング(OOP)のスタイルのひとつであり、オブジェクトの生成に既存オブジェクトの複製を用いるスタイルを指している。これには直後にメンバを拡充するための空オブジェクトの複製も含まれている。このスタイルは、インスタンスベース(Instance-based)とも呼ばれている。これと対比されるOOPスタイルにクラスベースがある。
プロトタイプベースOOPの原点はSmalltalk方言のSelfであり、Smalltalkのクラスベース設計を平易化する試みから1987年に誕生している。他にはLua、JavaScript、Etoys、ECMAScript、REBOL、Io、TypeScriptなどがある。
プロトタイプとは、複製元になったオブジェクトを意味しており、複製先のオブジェクトから見てそう呼ばれる。プロトタイプは同時にそのオブジェクトの暗黙の委譲先になり、これはプロトタイプを複製が継承していることと同じになる。
来歴
[編集]プロトタイプベースは、Smalltalkのクラスベース設計を平易化する試みから考案されたスタイルなので、Smalltalkの設計を知らないとそれが作られた理由も分からないものになる。ここではアラン・ケイが概略したSmalltalk設計の六項目を紹介して、クラスベースに関連する部分を和訳しておく[1]。
1, EverythingIsAnObject.(全てはオブジェクトである)2, Objects communicate by sending and receiving messages (in terms of objects).
3, Objects have their own memory (in terms of objects).(オブジェクトは自身の記憶を持つ)
4, Every object is an instance of a class (which must be an object).(全てのオブジェクトはクラスのインスタンスであり、クラスもまたオブジェクトである)
5, The class holds the shared behavior for its instances (in the form of objects in a program list).(クラスはそのインスタンスたちが共有する振る舞いを保持する)
6, To eval a program list, control is passed to the first object and the remainder is treated as its message.
(4)は数学的帰納な文章なので、インスタンスのひな型であるクラスもまたメタクラスのインスタンス化であり、そのメタクラスもまた他のメタクラスのインスタンス化であると解釈される。これは元祖クラスベースの大きな特徴であったが、実際はもう少し複雑でメタクラスとクラスの間に中間媒体が挟まれていた。i=インスタンス/C=クラス/M=メタクラスとするとインスタンス化の流れは、M → C class → C → iとなり、C classが中間媒体である。中間媒体は不変の静的型付け用としてオリジナルを保存し、クラスは可変の動的型付け用であった。
また、(3)で記憶(データ)はクラスとインスタンスの双方が持つが、(5)で振る舞い(メソッド)はクラスのみが保持するとされており、これも混乱を招きやすいネックになっていた。元祖クラスベース設計は理論面では美しかったが、実践面では甚だ複雑として開発陣からも不評になり、それは哲学的なインスタンス化チェーンと、クラスとインスタンスに対する振る舞いの妙に起因していた。
その改善策としての、オブジェクトからクラスとインスタンスの概念を無くしてしまおうという案が、プロトタイプベースの原点になっている。この案は言語視点では、クラスを無くしてインスタンスに一元化するとも解釈できるので、インスタンスベース(Instance-based)と別称された。クラスのインスタンス化を、インスタンスのクローンに置き換えることでSmalltalkクラス設計の改善が図られ、Selfはこの案に沿って制作されたSmalltalk方言であった。ここでは(1)の遵守が第一にされていた。
なお、C++/Pythonからの静的/動的クラスベース設計では、クラスとインスタンスを、型と値の役割に固定してインスタンス化の相互再帰を無くしたことから、インスタンスのみがオブジェクトになっている。メタクラスはクラス構成操作のリフレクション機能になっている。これは(1)の事実上の撤廃であった。
現在では、C++/Python発のクラスベース設計が多くの言語で採用されており、Self発のプロトタイプベースは少数派になっている。のみならずプロトタイプベースの代表格JavaScript、ECMAScriptではクラスベース構文が導入されるに到っており、TypeScriptはクラスベースとプロトタイプベースの折衷にされている。プロトタイプベースはやや汎用性に欠けてオブジェクト指向の主流にはなり得なかったという結論になる。
概要
[編集]Selfとは少し別の切り口から、Smalltalkクラスベース設計の平易化を図ったダグラス・クロックフォードは、JavaScriptのプロトタイプベースをこのように概略している[2]。
You make prototype objects, and then … make new instances. Objects are mutable in JavaScript, so we can augment the new instances, giving them new fields and methods. These can then act as prototypes for even newer objects. We don't need classes to make lots of similar objects… Objects inherit from objects. What could be more object oriented than that?
(あなたはプロトタイプ・オブジェクトと新しいインスタンスを作る。オブジェクトは可変であり、新フィールドと新メソッドを加えて拡充できる。これもまた新生オブジェクトのプロトタイプになる。クラスは必要ない。オブジェクトも同様に継承できるからだ。これ以上のオブジェクト指向があるだろうか?)
プロトタイプベースはプログラマに、オブジェクトをどう振る舞わせるかということのみに集中させて、オブジェクトが実際に振る舞えるかどうかの疑問を後回しにできる環境を提供する[3]。振る舞いとはメソッドである。疑問の後回しとは動的型付けのダックタイピングを意味している。プロトタイプベースは静的型付けの実装を排除してる訳ではないが、その特性と利点を最大限に活かすための動的型付けが好まれている。
プロトタイプベースのオブジェクトは総じて、スロットの可変長配列として実装されている。スロットとは「シンボル+コンテンツ」のペアデータである。シンボルはプロパティ名やメソッド名を表わし、コンテンツはプロパティ値やコードブロック参照を表わす。プロパティスロットはプロトタイプ参照やthis参照(self参照)の容器にもなる。Selfではメソッドスロットがメッセージ式で送られるセレクタの受け手になる。
オブジェクトの構築は、クローン方式かエクスニヒロ方式で行われる。クローン(clone)は既存オブジェクトを複製する方式であり、複製後にプロパティ/メソッドの自由な取り付け取り外しもできる。エクスニヒロ(ex nihilo)はプロパティ無しメソッド無しの空オブジェクトを生成(または複製)する方式であり、生成後にプロパティ/メソッドの自由な取り付けができる。構造体に似た書式でプロパティ/メソッドを初期設定して生成する方式もエクスニヒロに分類されている。クラス概念がないのでテンプレート処理的なオブジェクト構築は不可であるが、クラスベース構文が導入された言語では代替的に可能にされており、それはエクスニヒロの方で解釈されている。
クローンで構築されたオブジェクトのプロトタイプ-スロットには、クローン元になったオブジェクトの参照が自動代入される。プロトタイプ-スロットは再代入可能なので、エクスニヒロで構築された空オブジェクトにも、そのプロトタイプにするオブジェクト参照を自由に追加できた。プロトタイプは暗黙の委譲先になり、オブジェクトがアクセス要求されたプロパティ/メソッドを持っていない場合は、そのプロトタイプで自動サーチされる。これは継承になった。
プロトタイプベースのポリモーフィズムは、クラスがないことからメソッドオーバーライドによる仮想関数は成立しないが、オブジェクトの構造的型付け解釈によるメソッドのサブタイピングがそれを担っている。また、動的型付けによる動的バインディングも用いられる。
プロトタイプベースでは、カプセル化は軽視されていることが多い。
脚注
[編集]- ^ “The Early History Of Smalltalk”. 2019年1月閲覧。
- ^ Crockford, Douglas. “Prototypal Inheritance in JavaScript”. 22 June 2021閲覧。
- ^ Taivalsaari, Antero; Noble, James (1998). “Thinking with prototypes”. Addendum to the 1998 proceedings of the conference on Object-oriented programming, systems, languages, and applications (Addendum) - OOPSLA '98 Addendum (New York, New York, USA: ACM Press). doi:10.1145/346852.346949 .
参考文献
[編集]- Abadi, Martin; Luca Cardelli (1996). A Theory of Objects. Springer-Verlag. ISBN 978-1-4612-6445-3
- Class Warfare: Classes vs. Prototypes, by Brian Foote.
- Noble, James; Taivalsaari, Antero; Moore, Ivan, eds (1999). Prototype-Based Programming: Concepts, Languages and Applications. Springer-Verlag. ISBN 981-4021-25-3
- Using Prototypical Objects to Implement Shared Behavior in Object Oriented Systems, by Henry Lieberman, 1986.