Common Lisp is dynamically typed: values have types, variables do not. A type is a set of objects; a type specifier is a symbol or list that names one. Declarations let the programmer promise types to the compiler, which can use them for speed or checking.
The type hierarchy
Every object is of type t; nil is the type with no objects. The standard types below it:
| Type | Subtypes |
|---|---|
number | real (rational: integer (fixnum, bignum), ratio; float: short-float, single-float, double-float, long-float) and complex |
character | base-char (standard-char), extended-char |
symbol | keyword, null (the symbol nil), boolean (t and nil) |
sequence | list (cons, null) and vector (string, bit-vector, simple-vector, …) |
array | vector, simple-array, string, base-string, simple-string, bit-vector, simple-bit-vector, simple-base-string |
function | compiled-function, generic-function, standard-generic-function |
stream | broadcast-stream, concatenated-stream, echo-stream, file-stream, string-stream, synonym-stream, two-way-stream |
| others | hash-table, package, pathname (logical-pathname), random-state, readtable, restart, class and its subtypes, method, method-combination, structure-object, standard-object, condition and the condition types |
The range of fixnum is at least −215 to 215−1 in the standard, and in practice 62 bits in SBCL on 64-bit machines (most-positive-fixnum is 4611686018427387903 there). The limits are the constants most-positive-fixnum, most-negative-fixnum, array-dimension-limit, array-rank-limit, array-total-size-limit, char-code-limit, call-arguments-limit, lambda-parameters-limit, multiple-values-limit, the float limits (most-positive-double-float, least-positive-normalized-double-float, double-float-epsilon and the same for short, single and long), and internal-time-units-per-second.
Type specifiers
| Specifier | Meaning |
|---|---|
(and type*), (or type*), (not type) | intersection, union and complement |
(member object*), (eql object) | exactly these objects (compared by eql) |
(satisfies predicate) | objects for which the named predicate is true; opaque to the compiler |
(values type*) | for the and ftype only: types of multiple values, with &optional and &rest |
(mod n) | the integers 0 to n−1 |
(integer low high), (rational low high), (float low high), (real …) and the float types | a range; each bound is a number, a list of one number (exclusive), or * (no limit): (integer 0 *), (double-float (0d0) 1d0) |
(unsigned-byte n), (signed-byte n) | integers that fit n bits; bit is (unsigned-byte 1) |
(complex type) | complex numbers with parts of the given type |
(cons car-type cdr-type) | conses |
(array element-type dimensions), (simple-array …), (vector element-type size), (simple-vector size), (string size), (simple-string size), (bit-vector size) | arrays; * for any element type, rank or size; dimensions are a list or a rank: (array double-float (3 3)), (simple-array (unsigned-byte 8) (*)) |
(function (arg-type*) value-type) | function types, with &optional, &rest and &key; used in ftype; typep only tests for function |
| a class name | the names of classes (defclass), structures (defstruct) and condition types are type specifiers |
deftype defines a new specifier that expands to another: (deftype octet () '(unsigned-byte 8)), (deftype list-of (type) …). The functions are typep, subtypep (two values: answer and certainty), type-of, coerce, upgraded-array-element-type, upgraded-complex-part-type, check-type, typecase (and etypecase, ctypecase), the and the :type slot options and of-type in loop. Specialising generic function methods on types is described in CLOS. The viewer colours the standard type names, where a type is expected, as types; list, string, integer, number, symbol, function, stream, class, method, package and the like are also common variable names, so it colours them only in declarations, after the, in type-testing forms, after :type and :element-type and in quoted type specifiers.
Declarations
A declaration is (declare spec*) at the start of the body of a binding form (let, let*, flet, labels, lambda, defun, defmethod, do, dolist, multiple-value-bind, destructuring-bind, with-open-file, …) or in locally; globally, (declaim spec*) (or the function proclaim). A declaration is advice that the compiler may use, except special, inline and notinline and dynamic-extent, which change what the program does, and it is an error for a declared type not to hold (with safety 0, undefined).
| Declaration | Meaning |
|---|---|
(type type var*), or (type-name var*) | the variables hold values of this type: (declare (type fixnum i)) and (declare (fixnum i)) are the same |
(ftype function-type name*) | the type of functions: (declaim (ftype (function (fixnum) fixnum) f)) |
(function name arg-types result-type) | the form of ftype from CLtL1, which is not in the ANSI list of declarations; some programs still use it |
(special var*) | the variables are dynamic (special): a binding is visible to every function called from it |
(inline function*), (notinline function*) | asks the compiler to open-code a call, or not to |
(ignore var*), (ignorable var*) | the variable is never used (ignore) or may be unused (ignorable), so no style warning; also for functions: (ignore (function f)) |
(dynamic-extent var* (function f)*) | the value or closure need not outlive the form, so it can be on the stack |
(optimize (quality value)*) | sets the priorities of the compiler: speed, safety, debug, space, compilation-speed, each from 0 (unimportant) to 3 (most important), 1 by default; a bare quality means 3 |
(declaration name*) | tells the compiler that a name may be used as a new kind of declaration by tools |
(declaim (optimize (speed 3) (safety 1) (debug 0))
(ftype (function ((simple-array double-float (*))) double-float) sum))
(defun sum (v)
(declare (type (simple-array double-float (*)) v))
(let ((total 0d0))
(declare (type double-float total))
(dotimes (i (length v) total)
(incf total (aref v i)))))
Implementations add their own qualities and declarations: SBCL has sb-ext:muffle-conditions, sb-ext:freeze-type, sb-ext:truly-dynamic-extent, and the qualities sb-ext:inhibit-warnings and sb-c::insert-debug-catch; CCL and others differ. They are not standard and the viewer does not know them.