Common Lisp Object System
The Common Lisp Object System is the facility for object-oriented programming which is part of ANSI Common Lisp. CLOS is a powerful dynamic object system which differs radically from the OOP facilities found in more static languages such as C++ or Java. CLOS was inspired by earlier Lisp object systems such as MIT Flavors and CommonLoops, although it is more general than either. Originally proposed as an add-on, CLOS was adopted as part of the ANSI standard for Common Lisp and has been adapted into other Lisp dialects such as EuLisp or Emacs Lisp.
Features
The basic building blocks of CLOS are classes and their methods, instances of those classes, and generic functions.CLOS provides macros to define those:
defclass
, defmethod
, and defgeneric
. Instances are created with the method make-instance
.Classes can have multiple superclasses, a list of slots and a special metaclass. Slots can be allocated by class or by instance. Each slot has a name and the value of a slot can be accessed by that name using the function
slot-value
. Additionally special generic functions can be defined to write or read values of slots. Each slot in a CLOS class must have a unique name.CLOS is a multiple dispatch system. This means that methods can be specialized upon any or all of their required arguments. Most OO languages are single-dispatch, meaning that methods are only specialized on the first argument. Another unusual feature is that methods do not "belong" to classes; classes do not provide a namespace for generic functions or methods. Methods are defined separately from classes, and they have no special access to class slots.
Methods in CLOS are grouped into generic functions. A generic function is an object which is callable like a function and which associates a collection of methods with a shared name and argument structure, each specialized for different arguments. Since Common Lisp provides non-CLOS classes for structures and built-in data types, CLOS dispatch works also with these non-CLOS classes. CLOS also supports dispatch over individual objects. CLOS does not by default support dispatch over all Common Lisp data types. However, most Common Lisp implementations provide a metaobject protocol which allows generic functions to provide application specific specialization and dispatch rules.
Dispatch in CLOS is also different from most OO languages:
- Given a list of arguments, a list of applicable methods is determined.
- This list is sorted according to the specificity of their parameter specializers.
- Selected methods from this list are then combined into an effective method using the method combination used by the generic function.
- The effective method is then called with the original arguments.
For example,
; declare the common argument structure prototype
; define an implementation for, where t matches all types
1)
=> 1
; define an implementation for
) 2)
=> 2 ; dispatch changed at runtime
Like the OO systems in most dynamic languages, CLOS does not enforce encapsulation. Any slot can be accessed using the
slot-value
function or via accessor methods. To access it via slot-value
you have to know the name of the slot. CL programmers use the language's package facility to declare which functions or data structures are intended for export.Apart from normal methods, there also are
:before
, :after
, and :around
"auxiliary" methods. The former two are invoked prior to, or after the primary method, in a particular order based on the class hierarchy. An :around
method can control whether the primary method is executed at all. Additionally, the programmer can specify whether all possible primary methods along the class hierarchy should be called or just the one providing the closest match.The Standard Method-Combination provides the primary, before, after and around methods explained above. There are other Method-Combinations with other method types. New Method-Combinations and method types can be defined.
CLOS allows multiple inheritance. When the default order in which methods are executed in multiple inheritance is not correct, the programmer may resolve the diamond inheritance problems by specifying the order of method combinations.
CLOS is dynamic, meaning that not only the contents, but also the structure of its objects can be modified at runtime. CLOS supports changing class definitions on-the-fly as well as changing the class membership of a given instance through the
change-class
operator. CLOS also allows one to add, redefine and remove methods at runtime. The Circle-Ellipse Problem is readily solved in CLOS, and most OOP design patterns either disappear or are qualitatively simpler.CLOS is not a prototype language: Classes must be defined before objects can be instantiated as members of that class.
Metaobject Protocol
Outside of the ANSI Common Lisp standard, there is a widely implemented extension to CLOS called the Metaobject Protocol. The MOP defines a standard interface to the underpinnings of the CLOS implementation, treating classes, slot-descriptions, generic-functions and methods themselves as instances of metaclasses, and allows the definition of new metaclasses and the modification of all CLOS behavior. The flexibility of the CLOS MOP prefigures aspect-oriented programming, which was later developed by some of the same engineers, such as Gregor Kiczales. The MOP defines the behavior of the whole object system by a set of protocols. These are defined in terms of CLOS. Thus it is possible to create new object-systems by extending or changing the provided CLOS functionality. The book The Art of the Metaobject Protocol describes the use and implementation of the CLOS MOP.The various Common Lisp implementations have slightly different support for the Meta-Object Protocol. The Closer project aims to provide the missing features.
Influences from older Lisp-based object systems
was the object system on the MIT Lisp Machine. Large parts of the Lisp Machine operating systems and many applications for it use Flavors or New Flavors. Flavors introduced multiple inheritance and mixins, among other features. Flavors is mostly obsolete, though implementations for Common Lisp do exist. Flavors was using the message passing paradigm. New Flavors introduced generic functions.CommonLoops was the successor of LOOPS . CommonLoops was implemented for Common Lisp. A portable implementation called Portable CommonLoops was the first implementation of CLOS. PCL is widely ported and still provides the base for the CLOS implementation of several Common Lisp implementations. PCL is implemented mostly in portable Common Lisp with only a few system dependent parts.
CLOS in other programming languages
Because of the power and expressivity of CLOS, as well as the historical availability of TinyCLOS, CLOS-like MOP-based object systems have become the de facto norm in most Lisp dialect implementations, as well as finding their way into some other languages' OOP facilities:- COS, the C Object System
- Dylan
- for Emacs Lisp.
- , Scheme with CLOS
- in GNU Guile
- ILOS in ISLISP
- , an Object System in Scheme
- , a Scheme with CLOS
- , for Scheme
- for MIT Scheme
- , a Scheme with CLOS
- in Racket
- in Chicken Scheme
- VCLOS for Skill
Literature
- Sonya Keene, ', 1988, Addison-Wesley.
- Gregor Kiczales, Jim des Rivieres, and Daniel G. Bobrow, The Art of the Metaobject Protocol, 1991, MIT Press.
- Jo A. Lawless and Molly M. Miller, ', 1991, Digital Press,
- Andreas Paepcke, , 1993, The MIT Press.
- by Richard P. Gabriel and Linda DeMichiel provides a good introduction to the motivation for defining classes by means of generic functions.
- 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,