Common Lisp the Language, 2nd Edition

Next: Type Conversion Function Up: Type Specifiers Previous: Type Specifiers That

# 4.7. Defining New Type Specifiers

New type specifiers can come into existence in two ways. First, defining a new structure type with `defstruct` automatically causes the name of the structure to be a new type specifier symbol. Second, the `deftype` special form can be used to define new type-specifier abbreviations.

[Macro]
`deftype` `name` `lambda-list` [[`{declaration}*` `|` `doc-string`]] `{form}*`

This is very similar to a `defmacro` form: name is the symbol that identifies the type specifier being defined, lambda-list is a lambda-list (and may contain `&optional` and `&rest` markers), and the forms constitute the body of the expander function. If we view a type specifier list as a list containing the type specifier name and some argument forms, the argument forms (unevaluated) are bound to the corresponding parameters in lambda-list. Then the body forms are evaluated as an implicit `progn`, and the value of the last form is interpreted as a new type specifier for which the original specifier was an abbreviation. The name is returned as the value of the `deftype` form.

`deftype` differs from `defmacro` in that if no initform is specified for an `&optional` parameter, the default value is `*`, not `nil`.

If the optional documentation string doc-string is present, then it is attached to the name as a documentation string of type `type`; see `documentation`.

Here are some examples of the use of `deftype`:

    (deftype mod (n) `(integer 0 (,n)))

    (deftype list () '(or null cons))

    (deftype square-matrix (&optional type size)
      "SQUARE-MATRIX includes all square two-dimensional arrays."
      `(array ,type (,size ,size)))

    (square-matrix short-float 7)  means  (array short-float (7 7))

    (square-matrix bit)  means  (array bit (* *))

If the type name defined by `deftype` is used simply as a type specifier symbol, it is interpreted as a type specifier list with no argument forms. Thus, in the example above, `square-matrix` would mean `(array * (* *))`, the set of two-dimensional arrays. This would unfortunately fail to convey the constraint that the two dimensions be the same; `(square-matrix bit)` has the same problem. A better definition is

    (defun equidimensional (a)
      (or (< (array-rank a) 2)
          (apply #'= (array-dimensions a))))

    (deftype square-matrix (&optional type size)
      `(and (array ,type (,size ,size))
            (satisfies equidimensional)))

X3J13 voted in March 1988 (FLET-IMPLICIT-BLOCK) to specify that the body of the expander function defined by `deftype` is implicitly enclosed in a `block` construct whose name is the same as the name of the defined type. Therefore `return-from` may be used to exit from the function.

X3J13 voted in March 1989 (DEFINING-MACROS-NON-TOP-LEVEL) to clarify that, while defining forms normally appear at top level, it is meaningful to place them in non-top-level contexts; `deftype` must define the expander function within the enclosing lexical environment, not within the global environment.

Next: Type Conversion Function Up: Type Specifiers Previous: Type Specifiers That