
Common Lisp オブジェクト システム (CLOS) は、ANSI Common Lispにおけるオブジェクト指向プログラミングの機能です。CLOS は強力な動的オブジェクト システムであり、 C++やJavaなどの静的な言語に見られる OOP 機能とは根本的に異なります。CLOS はMIT FlavorsやCommonLoopsなどの初期の Lisp オブジェクト システムにヒントを得ていますが、どちらよりも汎用的です。CLOS はもともとアドオンとして提案されましたが、Common Lisp の ANSI 標準の一部として採用され、 EuLispやEmacs Lispなどの他の Lisp 方言にも採用されています。[1]
特徴
CLOS の基本的な構成要素は、メソッド、クラス、それらのクラスのインスタンス、およびジェネリック関数です。CLOS は、これらを定義するためのマクロを提供します: defclass、、defmethodおよびdefgeneric。インスタンスはメソッドを使用して作成されますmake-instance。
クラスは、複数のスーパークラス、スロットのリスト (C++/Java 用語ではメンバー変数)、および特別なメタクラスを持つことができます。スロットは、クラス (クラスのすべてのインスタンスがスロットを共有) またはインスタンスによって割り当てることができます。各スロットには名前があり、関数を使用してその名前でスロットの値にアクセスできますslot-value。さらに、スロットの値の書き込みまたは読み取りを行うための特別な汎用関数を定義することもできます。CLOS クラスの各スロットには、一意の名前を付ける必要があります。
CLOS は多重ディスパッチシステムです。つまり、メソッドは必要な引数の一部またはすべてに特化できます。ほとんどの OO 言語は単一ディスパッチであり、メソッドは最初の引数にのみ特化されます。もう 1 つの珍しい特徴は、メソッドがクラスに「属さない」ことです。クラスは汎用関数またはメソッドの名前空間を提供しません。メソッドはクラスとは別に定義され、クラス スロットへの特別なアクセス (例: 「this」、「self」、「protected」) はありません。
CLOS のメソッドは、ジェネリック関数にグループ化されます。ジェネリック関数は、関数のように呼び出し可能で、共有の名前と引数構造を持つメソッドのコレクションを関連付けるオブジェクトです。各メソッドは、異なる引数に特化されています。Common Lisp は、構造体と組み込みデータ型 (数値、文字列、文字、シンボルなど) に対して非 CLOS クラスを提供するため、CLOS ディスパッチはこれらの非 CLOS クラスでも機能します。CLOS は、個々のオブジェクト (eql スペシャライザ) に対するディスパッチもサポートしています。CLOS は、デフォルトではすべての Common Lisp データ型に対するディスパッチをサポートしていません (たとえば、ディスパッチは、完全に特化された配列型や によって導入された型では機能しません)。ただし、ほとんどの Common Lisp 実装では、ジェネリック関数がアプリケーション固有の特化とディスパッチ規則を提供できるようにするメタオブジェクト プロトコルdeftypeが提供されています。
CLOS のディスパッチも、ほとんどの OO 言語とは異なります。
- 引数のリストが与えられると、適用可能なメソッドのリストが決定されます。
- このリストは、パラメータ スペシャライザの特異性に従ってソートされます。
- このリストから選択されたメソッドは、ジェネリック関数で使用されるメソッドの組み合わせを使用して、有効なメソッドに結合されます。
- その後、有効なメソッドが元の引数で呼び出されます。
このディスパッチ メカニズムは実行時に機能します。そのため、メソッドを追加または削除すると、実行時に有効なメソッドが変更される場合があります (ジェネリック関数が同じ引数で呼び出される場合でも)。メソッドの組み合わせを変更すると、有効なメソッドが異なる場合があります。
例えば、
; 共通引数構造プロトタイプを宣言します。
( defgeneric f ( x y ))
; (f integer y) の実装を定義します。ここで、y はすべての型に一致します。
( defmethod f (( x integer ) y ) 1 )
(f 1 2.0 )=> 1
; (f integer real) の実装を定義します。
( defmethod f (( x integer ) ( y real )) 2 )
( f 1 2.0 ) => 2 ;実行時にディスパッチが変更されました。
ほとんどの動的言語の OO システムと同様に、CLOS はカプセル化を強制しません。slot-value関数を使用するか、(オプションで自動生成される)アクセサ メソッドを介して、任意のスロットにアクセスできます。を介してアクセスするには、slot-valueスロットの名前を知っている必要があります。 CL プログラマーは、言語のパッケージ機能を使用して、どの関数またはデータ構造がエクスポート用であるかを宣言します。
通常の (「プライマリ」) メソッドの他に、、、および「補助」メソッドもあります:before。:after最初:aroundの 2 つは、クラス階層に基づいて特定の順序でプライマリ メソッドの前または後に呼び出されます。メソッドは、プライマリ メソッドが実行されるかどうかを制御できます。さらに、プログラマーは、クラス階層:aroundに沿ってすべてのプライマリ メソッドを呼び出すか、最も近い一致を提供するプライマリ メソッドだけを呼び出すかを指定できます。
標準メソッドの組み合わせは、上で説明したプライマリ、前、後、および周辺のメソッドを提供します。他のメソッド タイプとのその他のメソッドの組み合わせもあります。新しい (単純なものから複雑なものまで) メソッドの組み合わせとメソッド タイプを定義できます。
CLOS は多重継承を許可します。多重継承でメソッドが実行されるデフォルトの順序が正しくない場合、プログラマーはメソッドの組み合わせの順序を指定することによって ダイヤモンド継承の問題を解決できます。
CLOS は動的であり、つまり、その内容だけでなく、オブジェクトの構造も実行時に変更できます。CLOS は、クラス定義をオンザフライで変更すること (問題のクラスのインスタンスがすでに存在する場合でも) と、演算子を使用して特定のインスタンスのクラス メンバーシップを変更することをサポートしていますchange-class。CLOS では、実行時にメソッドを追加、再定義、削除することもできます。円-楕円問題はCLOS で簡単に解決され、ほとんどの OOPデザイン パターンはなくなるか、質的に単純化されます。[2]
CLOS はプロトタイプ言語ではありません。オブジェクトをそのクラスのメンバーとしてインスタンス化する前に、クラスを定義する必要があります。
メタオブジェクトプロトコル
ANSI Common Lisp 標準の外には、メタオブジェクトプロトコル (MOP) と呼ばれる CLOS の拡張が広く実装されています。MOP は、CLOS 実装の基盤への標準インターフェイスを定義し、クラス、スロット記述、ジェネリック関数、メソッド自体をメタクラスのインスタンスとして扱い、新しいメタクラスの定義とすべての CLOS 動作の変更を可能にします。CLOS MOP の柔軟性は、後にGregor Kiczalesなどの同じエンジニアによって開発されたアスペクト指向プログラミングの前兆です。MOP は、一連のプロトコルによってオブジェクト システム全体の動作を定義します。これらは CLOS の観点から定義されます。したがって、提供されている CLOS 機能を拡張または変更することで、新しいオブジェクト システムを作成できます。The Art of the Metaobject Protocolという書籍では、 CLOS MOP の使用と実装について説明しています。
さまざまなCommon Lisp実装では、メタオブジェクトプロトコルのサポートが若干異なります。Closer [3]プロジェクトは、不足している機能を提供することを目指しています。
古いLispベースのオブジェクトシステムからの影響
Flavors (およびその後継の New Flavors) は、MIT Lisp Machine上のオブジェクト システムでした。Lisp Machine オペレーティング システムの大部分と、その多くのアプリケーションは、Flavors または New Flavors を使用しています。Flavors は、多重継承やミックスインなどの機能を導入しました。Flavors はほとんど廃止されていますが、Common Lisp の実装は存在します。Flavors はメッセージ パッシング パラダイムを使用していました。New Flavors は、ジェネリック関数を導入しました。
CommonLoops はLOOPS (Xerox Interlisp -Dから) の後継です。CommonLoops は Common Lisp 用に実装されました。Portable CommonLoops (PCL) と呼ばれる移植可能な実装は、CLOS の最初の実装でした。PCL は広く移植されており、現在でもいくつかのCommon Lisp実装の CLOS 実装のベースとなっています。PCL は、システムに依存する部分をいくつか除いて、ほとんどが移植可能な Common Lisp で実装されています。
他のプログラミング言語におけるCLOS
CLOS のパワーと表現力、そして Tiny CLOS ( Gregor KiczalesがScheme で使用するために作成した、簡素化された移植可能な CLOS 実装) が歴史的に利用可能であったため、CLOS のような MOP ベースのオブジェクト システムは、ほとんどの Lisp 方言実装の事実上の標準となり、他の言語のOOP機能にも取り入れられています。
- COS、Cオブジェクトシステム[4]
- ディラン
- Dynace、C言語による(主に)CLOS実装[5]
- Emacs Lisp 用の EIEIO
- Gauche、CLOS を使用した Scheme
- GNU Guileの GOOPS
- ISLISPの ILOS
- Meroon、Scheme のオブジェクト システム
- CLOS を使用したスキーム、Sagittarius
- ScmObj(Scheme用)
- MIT スキームの SOS
- STklos、CLOS を使用したスキーム
- 詐欺行為
- チキン計画におけるCOOPS
- スキルのためのVCLOS [6]
- タイニーCLOS [7]
- SおよびRプログラミング言語の S4 クラス
さらに読む
- Bobrow, Daniel G. ; Kahn, Kenneth; Kiczales, Gregor ; Masinter, Larry ; Stefik, Mark; Zdybel, Frank (1986年6 月)。「CommonLoops: Lisp とオブジェクト指向プログラミングの融合」(PDF)。オブジェクト指向プログラミング システム言語とアプリケーションに関する会議議事録。OOPSLA '86 。pp. 17–29。doi :10.1145/ 28697.28700。ISBN 978-0-89791-204-4. S2CID 62631315. 2022年8月17日時点の オリジナル(PDF)からアーカイブ。 2022年3月17日閲覧。
- Veitch, Jim (1998)。「CLOS の歴史と説明」。Salus , Peter H. (編) 著。プログラミング言語ハンドブック、第 4 巻: 関数型プログラミング言語と論理型プログラミング言語(第 1 版)。Macmillan Technical Publishing。107 ~ 158 ページ。ISBN 1-57870-011-6。
参考文献
- ^ 「CLOS は標準です。複数のベンダーが CLOS を供給しています。CLOS (またはその一部) は、EuLisp や Emacs Lisp などの他の Lisp 方言にオブジェクト指向を追加するために使用されています。」Veitch 1998 の 110 ページ
- ^ 「動的言語のデザイン パターン」のスライドで、Peter Norvig は、さまざまな教科書から引用した 23 のデザイン パターンのうち 16 が、C++ よりも Dylan または Common Lisp では「見えないか、または単純」であるという調査結果を示しています。
- ^ Closer プロジェクト: MOP に近づく
- ^ Deniau, Laurent (2010年3月12日). Cオブジェクトシステム: Cを高水準オブジェクト指向言語として使用する(PDF) . arXiv : 1003.2547 . CiteSeerX 10.1.1.763.7946 . 2022年3月17日閲覧。
- ^ Dynace オブジェクト指向 C 拡張
- ^ Newton, Jim; Rhodes, Christophe (2008年11月28日). 「オブジェクト指向Lispのカスタムスペシャライザー」. Journal of Universal Computer Science . 14 (20): 3370–3388. CiteSeerX 10.1.1.523.2413 . doi : 10.3217/jucs-014-20-3370 . S2CID 12032836. 2022年3月17日閲覧。
- ^ Gregor Kiczales が開発した Tiny CLOS
文学
- Sonya Keene、『Common Lisp でのオブジェクト指向プログラミング: CLOS プログラマーガイド』 、1988 年、Addison - Wesley。ISBN 0-201-17589-4
- Gregor Kiczales、Jim des Rivieres、Daniel G. Bobrow 、『The Art of the Metaobject Protocol』、1991年、MIT Press。ISBN 0-262-61074-4
- Jo A. Lawless および Molly M. Miller、「Understanding CLOS: the Common Lisp Object System」、1991 年、Digital Press、ISBN 1-55558-064-5
- Andreas Paepcke、『オブジェクト指向プログラミング: CLOS の視点』、 1993 年、MIT 出版。ISBN 0-262-16136-2
- Richard P. Gabrielと Linda DeMichielによる「The Common Lisp Object System: An Overview」は、ジェネリック関数を使用してクラスを定義する動機について優れた入門書です。
- Nick Levine 著の Fundamentals of CLOS では、CLOS での OO コンセプトの実装とその活用方法を段階的に説明しています。Lisp または Scheme の基礎知識を持つ人を対象としています。
- Common Lisp HyperSpec、第 7 章: オブジェクト
