CLOS is the object system built into Common Lisp. Behaviour belongs to generic functions, not to classes: a generic function is a function whose body is chosen, on each call, from a set of methods by the classes (or identities) of its arguments. Classes only hold slots and form a hierarchy with multiple inheritance. It was added to the language between CLtL1 and the ANSI standard, in the 1988 specification by X3J13 and in chapters 7 and 28 of CLtL2.
Classes
(defclass name (direct-superclass*) (slot-specifier*) class-option*). A slot specifier is a name, or (name option*) with these options:
| Option | Meaning |
|---|---|
:reader name | defines a generic function returning the slot value |
:writer name | defines a generic function (name new-value instance); (setf x) names work |
:accessor name | defines a reader and a (setf name) writer |
:initarg keyword | a keyword argument of make-instance that sets the slot; there may be several |
:initform form | a form evaluated for the slot if no initarg gave a value |
:type type | the type the value should have; implementations may check it |
:allocation :instance | :class | per instance (default), or shared by all instances of the class |
:documentation string | a documentation string |
The class options are (:default-initargs initarg value-form …), (:documentation string) and (:metaclass class-name). A class’s class precedence list puts each class before its superclasses and keeps the order of each class’s direct superclass list; t and standard-object come last. Slots with the same name in several classes are merged, taking the first initform and uniting the initargs. A class defined again updates its existing instances through update-instance-for-redefined-class. change-class changes the class of an existing instance, calling update-instance-for-different-class.
(defclass shape ()
((name :initarg :name :accessor shape-name :initform "shape")
(count :allocation :class :initform 0 :accessor shape-count)))
(defclass circle (shape)
((radius :initarg :radius :reader radius :type real))
(:default-initargs :name "circle"))
(defgeneric area (shape)
(:documentation "The area of SHAPE."))
(defmethod area ((c circle))
(* pi (expt (radius c) 2)))
(defmethod area ((s (eql :unit)))
1)
(defmethod print-object ((c circle) stream)
(print-unreadable-object (c stream :type t)
(format stream "r=~a" (radius c))))
eql value) and a print-object method.Generic functions and methods
(defgeneric name lambda-list option* method-description*) options: (:argument-precedence-order …), (declare …), (:documentation …), (:method-combination name arg*), (:generic-function-class class), (:method-class class), and (:method …) descriptions. A defmethod without a prior defgeneric makes the generic function implicitly. All methods of a generic function have congruent lambda lists: the same required parameters and the same optional ones, and keywords the function accepts.
A method’s required parameters are specialised: (var class-name) (a class or a structure type), (var (eql form)) (form is evaluated once, when the method is defined), or plain var for t. Built-in types are classes too, so methods can specialise on integer, string, list, null, symbol and others. Dispatch is on every required argument, left to right unless :argument-precedence-order says otherwise.
Calling a generic function finds the applicable methods (those whose specialisers match), sorts them most specific first by the class precedence lists of the arguments, and combines them with the method combination to make the effective method. Inside a method, (call-next-method) calls the next method (with the same arguments, or with new ones given), and (next-method-p) tells if there is one. If no method applies, no-applicable-method is called (which signals an error); if call-next-method has none, no-next-method.
Method combination
The default is standard. A method has at most one qualifier, and the standard combination builds the effective method like this:
- all
:aroundmethods, most specific first.call-next-methodfrom the last of them runs the rest; - all
:beforemethods, most specific first; - the most specific primary method (no qualifier), which can call the less specific ones with
call-next-method; - all
:aftermethods, least specific first. The value of the generic function is that of the primary (or:around) method, not the:afterones.
The simple built-in combinations are named by the operator that joins the primary methods’ values: +, and, append, list, max, min, nconc, or and progn. They are chosen with (:method-combination +) in defgeneric and take the operator as the qualifier of every method ((defmethod size + ((x a)) …)), with :around still allowed, and an optional :most-specific-first or :most-specific-last argument. define-method-combination defines others, in a short form ((define-method-combination name :operator op :identity-with-one-argument t)) or a long form that uses call-method, make-method and a method-group specification. method-qualifiers returns a method’s qualifiers; invalid-method-error and method-combination-error signal errors in a combination.
Objects and initialisation
(make-instance class initarg*)callsallocate-instance, theninitialize-instance, which callsshared-initialize. A program customises an object by defining:aftermethods oninitialize-instance;reinitialize-instanceandupdate-instance-for-redefined-classalso reachshared-initialize.- Slot access:
slot-value(a place),slot-boundp,slot-makunbound,slot-exists-p, and the macroswith-slotsandwith-accessors. An unbound slot callsslot-unbound; a missing oneslot-missing. class-of,find-class(a place),class-name,typepandsubtypepwith class names,ensure-generic-function,add-method,remove-method,find-method,compute-applicable-methods.- The functions the system calls for you and you can specialise:
print-object,describe-object,make-load-form(andmake-load-form-saving-slots),documentationand(setf documentation),function-keywords.
Standard classes
The classes of the standard are t at the root, standard-object (the default superclass of defclass), structure-object (of defstruct), the metaclasses standard-class, built-in-class and structure-class (and class), the function classes function, generic-function, standard-generic-function, method, standard-method and method-combination, and the classes of the built-in types such as number, integer, ratio, float, character, string, symbol, list, cons, null, vector, array, hash-table, stream and its subclasses, package, pathname, readtable, random-state and the conditions.
The Metaobject Protocol
The standard does not include the Metaobject Protocol (MOP): classes, slots, generic functions and methods are themselves objects with their own classes, and the MOP specifies how to change what they do, as described in The Art of the Metaobject Protocol (Kiczales, des Rivières and Bobrow, 1991). The standard leaves the classes of these objects open. The MOP is implemented, with small differences, by SBCL (sb-mop), CCL, CLISP, ECL, Allegro and LispWorks (clos and mop), and the library closer-mop gives one portable package. Its functions and classes (compute-class-precedence-list, finalize-inheritance, validate-superclass, slot-value-using-class, funcallable-standard-object and so on) are not described on these pages, and the viewer does not know them as standard names.