CLOS

**Common Lisp 物件系統**（**CLOS**）是一種物件導向程式設計設施，它是 ANSI Common Lisp 的一部份。CLOS 是強力的動態物件系統，在根本上不同於靜態語言，比如 C++ 或 Java 中的那種 OOP 設施。CLOS 受到更早期的 Lisp 物件系統，比如 MIT Flavors 和 Xerox CommonLoops 的啟發，然而它比二者要更加泛化。

## 歷史

CLOS 最初被提議作為一種附加件，首次出現在 1988 年發表的《Common Lisp 物件導向程式設計》，和 1990 年出版的《Common Lisp 語言》第二版（也叫做 CLtL2）中。在 1994 年，CLOS 被接受為 ANSI 標準 Common Lisp 的一部份，並且已經被適配入其他 Lisp 方言比如 EuLisp 和 Emacs Lisp 之中。

## 特徵

CLOS 的基本建造塊是類、方法、泛化函式和類別的實例。CLOS 提供了定義它們的宏：`defclass`、`defmethod` 和 `defgeneric`。實例通過方法 `make-instance` 來建立。CLOS 不是基於原型語言，類必須聲明於物件可以實例化為這個類的成員之前。

### 類

類是槽的一個列表，它可以有多個超類，和一個特定的元類。槽（C++/Java 用語中的成員變數），可以由類（一個類的所有實例共享這個槽）或實例來分配。每個槽都有一個名字，而一個槽的值可以使用函式 `slot-value`，通過這個名字來存取。可以定義額外的特定泛化函式，來寫或讀這些槽的值。在 CLOS 類中的每個槽，都必須有一個唯一的名字。

如同多數動態語言中的 OO 系統那樣，CLOS 不強制封裝。任何槽都可以使用 `slot-value` 函式，或通過（可選的自動生成的）存取子方法來存取。要通過 `slot-value` 進行存取，就要知道這個槽的名字。CL 編程者使用這個語言的包設施，來聲明哪些函式或資料結構意圖被匯出。

CLOS 允許多重繼承。在多重繼承中方法執行的預設次序不正確的時候，編程者可以通過指定方法組合的次序，來解決這種菱形繼承問題（類 D 同時繼承一個超類 A 的兩個子類 B 和 C，四者形成菱形，如果 A 的某一方法被 B 和 C 覆寫，D 該繼承二者中哪一個？）。在 CLOS 中已經解決了圓–橢圓問題（圓是橢圓的長軸與短軸相等的特殊情況，故而是其子類，但圓不能繼承橢圓的使得其不再為圓的方法，比如單獨改變長軸或短軸）。而多數 OOP 設計模式，要麼消失，要麼在性質上更加簡單了。

CLOS 是動態的，意味著不只是內容，它的物件的「結構」，也可以在執行時間修改。CLOS 支援現場（on-the-fly）變更類別定義，即使正在考慮的這個類別的實例已經存在；還有通過 `change-class` 算子，變更一個給定實例的類別成員關係。CLOS 還允許在執行時間增加、重新定義和移除方法。

### 多分派

CLOS 是一個多分派系統，這意味著方法，可以依據它們所要求的任何或所有實際參數來指定。多數 OO 語言是單分派的，意味著方法只能依據第一個實際參數來指定。其他不常見特徵是方法不「屬於」類；類不為泛化函式或方法提供命名空間。方法是獨立於類而定義的，並且它們對類的槽沒有特殊的存取（比如 `this`、`self` 或 `protected`）。

在 CLOS 中的方法被組織入泛化函式。泛化函式是像函式一樣可呼叫的一個物件，它關聯著有共享的名字和參數結構的方法的一個搜集，其中每個都特定於不同的實際參數。因為 Common Lisp 為結構和內建資料類型（數值、字串、字元、符號等）提供了非 CLOS 類，CLOS 分派也工作在這些非 CLOS 類之上。CLOS 還支援分派在個體物件之上（eql 特殊化者）。CLOS 預設的不支援分派於所有 Common Lisp 資料類型上，比如分派不工作於完全特殊化的陣列類型，或通過 `deftype` 介入的類型。然而多數 Common Lisp 實現，提供了元物件協定，它允許泛化函式提供特定於應用的特殊化和分派規則。例如採用 SBCL 演示的下述代碼：

### 方法組合

在 CLOS 中的分派還不同於多數 OO 語言：

1. 給出一個實際參數列，確定一個可應用的方法的列表。
2. 這個列表依據它們的形式參數的特殊化者（specializer）的特殊性（specificity）來排序。
3. 接著使用泛化函式所用的那個方法組合，將從這個列表選擇出的那些方法組合成一個有效方法。
4. 接著用最初的實際參數呼叫這個有效方法。

這個分派機制工作在執行時間。增加或移除方法，將導致在執行時間變更有效方法（即使在以相同實際參數呼叫泛化函式的時候）。變更方法組合還導致不同的有效方法。

除了常規（「主要」）方法之外，還有 `:before`、`:after` 和 `:around` 這些「輔助」方法。前兩個方法按照類別為基層級的特定次序，分別先於或後於主要方法而呼叫。`:around` 方法可能控制主要方法是否執行。此外，編程者可以指定沿著類層級的所有可能的主要方法，是都應當被呼叫，還是只呼叫提供最接近匹配的那個方法。

「標準方法組合」提供上述的主要、之前、之後和圍繞方法。還有具有其他方法類型的其他方法組合。可以定義新的（簡單和複雜二者）方法組合和方法類型。

## 元物件協定

在 ANSI Common Lisp 標準之外，有一個廣泛實現的對 CLOS 的擴充，叫做元物件協定（MOP）。MOP 定義到 CLOS 實現基礎支撐的標準介面，將類、槽描述、泛化函式和方法自身，當作元類的實例，並允許定義新的元類，和修改所有 CLOS 行為。CLOS MOP 的靈活性，預示了面向切面編程，它是由同一群工程師比如 Gregor Kiczales 開發的。MOP 通過一組協定，定義了整個物件系統的行為。這些定義是依據 CLOS 定義的。因此有可能通過擴充或變更已提供的 CLOS 系統的功能，來建立新的物件系統。1991 年出版的圖書《元物件協定的藝術》描述了 CLOS MOP 的使用和實現。

各種 Common Lisp 實現對元物件協定有稍微不同的支援。Closer 計劃致力於提供缺失的特徵。

## 來自更早的基於 Lisp 的物件系統的影響

Flavor（和它的後繼者 New Flavors），是 MIT Lisp 機器上的物件系統。Lisp 機器作業系統的很大部份和它的很多應用，使用了 Flavors 或 New Flavors。Flavors 介入了多重繼承和 mixin 和其他一些特徵。Flavors 幾乎廢止了，儘管存在針對 Common Lisp 實現。Flavors 使用訊息傳遞範式。New Flavors 介入了泛化函式。

CommonLoops，是 Xerox Interlisp-D 的 LOOPS 的後繼者。CommonLoops 是針對 Common Lisp 的實現。叫做可移植 CommonLoops（PCL）的可移植實現，是第一個 CLOS 實現。PCL 被廣泛的移植了，並仍為很多 Common Lisp 實現提供 CLOS 實現的基礎。PCL 絕大部份以可移植的 Common Lisp 實現，而只有很少的系統依賴部份。

## 其他語言中的 CLOS

由於 CLOS 的能力和表達力，還有歷史上能獲得到 TinyCLOS，它是 Gregor Kiczales 為用於 Scheme 而書寫的簡化的可移植的 CLOS 實現，故而類 CLOS 的基於 MOP 的物件系統，成為大多數 Lisp 方言實現的事實規範，還能在一些其他語言的 OOP 設施中找到它：

## 參照

## 延伸閱讀

* Jim Veitch. A History and Description of CLOS. Peter H. Salus (編). Handbook of Programming Languages, Volume IV: Functional and Logic Programming Languages. Macmillan Technical Publishing. 1998 (1st edition): 107–158. ISBN 1-57870-011-6.

## 參考文獻

* Sonya Keene. Object-Oriented Programming in Common Lisp: A Programmer's Guide to CLOS (PDF). Addison-Wesley. 1988 [2022-02-05]. ISBN0-201-17589-4. （原始內容 (PDF) 存檔於 2022-05-06）.
* Gregor Kiczales, Jim des Rivieres, Daniel G. Bobrow. The Art of the Metaobject Protocol (PDF). MIT Press. 1991 [2022-02-05]. ISBN0-262-61074-4. （原始內容 (PDF) 存檔於 2022-02-05）.
* Jo A. Lawless and Molly M. Miller, Understanding CLOS: the Common Lisp Object System, 1991, Digital Press, ISBN 1-55558-064-5
* Andreas Paepcke. Object-Oriented Programming: the CLOS Perspective. The MIT Press. 1993 [2022-02-05]. ISBN0-262-16136-2. （原始內容存檔於 2022-02-05）.
* The Common Lisp Object System: An Overview （頁面存檔備份，存於網際網路檔案館） by Richard P. Gabriel and Linda DeMichiel provides a good introduction to the motivation for defining classes by means of generic functions.
* Fundamentals of CLOS （頁面存檔備份，存於網際網路檔案館） by Nick Levine provides a step-by-step exposure to the implementation of OO concepts in CLOS, and how to utilize them. It is intended for anybody with a basic knowledge of Lisp or Scheme.
* Common Lisp HyperSpec, Chapter 7: Objects （頁面存檔備份，存於網際網路檔案館）