Common Lisp对象系统

Common Lisp对象系统（CLOS）是一种面向对象编程设施，它是ANSI Common Lisp的一部份。CLOS是强力的动态对象系统，在根本上不同于静态语言，比如C++或Java中的那种OOP设施。CLOS受到更早期的Lisp对象系统，比如MIT Flavors和Xerox CommonLoops的启发，然而它比二者要更加泛化。

**历史**
CLOS最初被提议作为一种附加件，首次出现在1988年发表的《Object-Oriented Programming in Common Lisp》，和1990年出版的《Common Lisp the Language》第二版（也叫做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中已经解决了Circle-ellipse problem（圆是椭圆的长轴与短轴相等的特殊情况，故而是其子类，但圆不能继承椭圆的使得其不再为圆的方法，比如单独改变长轴或短轴）。而多数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演示的下述代码：
 声明共同的实际参数结构原型- (defgeneric f (x y))
#
 定义对(f integer t)的实现，这里的t匹配所有类型- (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

**方法组合**
在ANSI common lisp中的标准方法组合，这里色泽最浅的是类A，类B是类A的子类，色泽最深的类C是类B的子类。合成有效方法的各个方法的执行次序是：①类A的:around方法、类B的:around方法、类C的:around方法，②类A的:before方法、类B的:before方法、类C的:before方法，③类A的主要方法、类B的主要方法、类C的主要方法，④类C的:after方法、类B的:after方法、类A的:after方法。
在CLOS中的分派还不同于多数OO语言：
# 给出一个实际参数列表，确定一个可应用的方法的列表。
# 这个列表依据它们的形式参数的特殊化者（specializer）的特殊性（specificity）来排序。
# 接着使用泛化函数所用的那个方法组合，将从这个列表选择出的那些方法组合成一个有效方法。
# 接着用最初的实际参数调用这个有效方法。
这个分派机制工作在运行时间。增加或移除方法，将导致在运行时间变更有效方法（即使在以相同实际参数调用泛化函数的时候）。变更方法组合还导致不同的有效方法。
除了常规（“主要”）方法之外，还有:before、:after和:around这些“辅助”方法。前两个方法按照基于类层级的特定次序，分别先于或后于主要方法而调用。:around方法可能控制主要方法是否执行。此外，编程者可以指定沿着类层级的所有可能的主要方法，是都应当被调用，还是只调用提供最接近匹配的那个方法。
“标准方法组合”提供上述的主要、之前、之后和围绕方法。还有具有其他方法类型的其他方法组合。可以定义新的（简单和复杂二者）方法组合和方法类型。

**元对象协议**
在ANSI Common Lisp标准之外，有一个广泛实现的对CLOS的扩展，叫做元对象协议（MOP）。MOP定义到CLOS实现基础支撑的标准接口，将类、槽描述、泛化函数和方法自身，当作元类的实例，并允许定义新的元类，和修改所有CLOS行为。CLOS MOP的灵活性，预示了面向方面编程，它是由同一群工程师比如Gregor Kiczales开发的。MOP通过一组协议，定义了整个对象系统的行为。这些定义是依据CLOS定义的。因此有可能通过扩展或变更已提供的CLOS系统的功能，来建立新的对象系统。1991年出版的图书《The Art of the Metaobject Protocol》描述了CLOS MOP的使用和实现。
各种Common Lisp实现对元对象协议有稍微不同的支持。Closer计划致力于提供缺失的特征。

**来自更早的基于Lisp的对象系统的影响**
（和它的后继者New Flavors），是MIT Lisp机器上的对象系统。Lisp机器操作系统的很大部份和它的很多应用，使用了Flavors或New Flavors。Flavors介入了多重继承和mixin和其他一些特征。Flavors几乎废止了，尽管存在针对Common Lisp实现。Flavors使用消息传递范型。New Flavors介入了泛化函数。
，是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设施中找到它：- COS，C对象系统 COS, the C Object System date=20140620141819 。- Dylan- Dynace，（很大程度上）CLOS的C实现。
*EIEIO，用于Emacs Lisp。- ILOS，用在ISLISP中。- PyCLOS，为Python 3实现了CLOS风格的泛化函数。
*具有CLOS的Scheme实现：
**Chicken Scheme使用COOPS。
**Gauche。
**GNU Guile使用GOOPS。
**MIT Scheme使用SOS。
**Sagittarius。
**STklos。- Meroon，用Scheme编写的对象系统。- R7RS CLOS，基于Tiny CLOS的具有语法糖的R7RS Scheme库。- Swindle，用在Racket中。- Tiny CLOS，Gregor Kiczales开发。

**引用**

**延伸阅读**

**参考文献**
 archive-url=https://web.archive.org/web/20220506070546/https://doc.lagout.org/programmation/Lisp/Object-Oriented%20Programming%20in%20Common%20Lisp_%20A%20Programmer%27s%20Guide%20to%20CLOS%20%5BKeene%201989-01-11%5D.pdf- Jo A. Lawless and Molly M. Miller, Understanding CLOS: the Common Lisp Object System, 1991, Digital Press, 1-55558-064-5- archive-url=https://web.archive.org/web/20220205100127/https://vdoc.pub/documents/object-oriented-programming-the-clos-perspective-6cf6hnm5eg20-  The Common Lisp Object System: An Overview date=20210324061255  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 date=20140610114656  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 date=20210425155557