Common Lisp the Language, 2nd Edition

Next: Specific Data Type Up: Data Type Predicates Previous: Data Type Predicates

## 6.2.1. General Type Predicates

If a data type is viewed as the set of all objects belonging to the type, then the `typep` function is a set membership test, while `subtypep` is a subset test.

[Function]
`typep` `object` `type`

`typep` is a predicate that is true if object is of type type, and is false otherwise. Note that an object can be ``of'' more than one type, since one type can include another. The type may be any of the type specifiers mentioned in chapter 4 except that it may not be or contain a type specifier list whose first element is `function` or `values`. A specifier of the form `(satisfies fn)` is handled simply by applying the function fn to object (see `funcall`); the object is considered to be of the specified type if the result is not `nil`.

X3J13 voted in January 1989 (ARRAY-TYPE-ELEMENT-TYPE-SEMANTICS) to change `typep` to give specialized `array` and `complex` type specifiers the same meaning for purposes of type discrimination as they have for declaration purposes. Of course, this also applies to such type specifiers as `vector` and `simple-array` (see section 4.5). Thus

    (typep foo '(array bignum))

in the first edition asked the question, Is `foo` an array specialized to hold bignums? but under the new interpretation asks the question, Could the array `foo` have resulted from giving `bignum` as the `:element-type` argument to `make-array`?

[Function]
`subtypep` `type1` `type2`

The arguments must be type specifiers that are acceptable to `typep`. The two type specifiers are compared; this predicate is true if type1 is definitely a (not necessarily proper) subtype of type2. If the result is `nil`, however, then type1 may or may not be a subtype of type2 (sometimes it is impossible to tell, especially when `satisfies` type specifiers are involved). A second returned value indicates the certainty of the result; if it is true, then the first value is an accurate indication of the subtype relationship. Thus there are three possible result combinations:

    t    t    type1 is definitely a subtype of type2
    nil  t    type1 is definitely not a subtype of type2
    nil  nil  subtypep could not determine the relationship

X3J13 voted in January 1989 (SUBTYPEP-TOO-VAGUE) to place certain requirements upon the implementation of `subtypep`, for it noted that implementations in many cases simply ``give up'' and return the two values `nil` and `nil` when in fact it would have been possible to determine the relationship between the given types. The requirements are as follows, where it is understood that a type specifier s involves a type specifier u if either s contains an occurrence of u directly or s contains a type specifier w defined by `deftype` whose expansion involves u.

- `subtypep` is not permitted to return a second value of `nil` unless one or both of its arguments involves `satisfies`, `and`, `or`, `not`, or `member`.

- `subtypep` should signal an error when one or both of its arguments involves `values` or the list form of the `function` type specifier.

- `subtypep` must always return the two values `t` and `t` in the case where its arguments, after expansion of specifiers defined by `deftype`, are `equal`.

In addition, X3J13 voted to clarify that in some cases the relationships between types as reflected by `subtypep` may be implementation-specific. For example, in an implementation supporting only one type of floating-point number, `(subtypep 'float 'long-float)` would return `t` and `t`, since the two types would be identical.

Note that `satisfies` is an exception because relationships between types involving `satisfies` are undecidable in general, but (as X3J13 noted) `and`, `or`, `not`, and `member` are merely very messy to deal with. In all likelihood these will not be addressed unless and until someone is willing to write a careful specification that covers all the cases for the processing of these type specifiers by `subtypep`. The requirements stated above were easy to state and probably suffice for most cases of interest.

X3J13 voted in January 1989 (ARRAY-TYPE-ELEMENT-TYPE-SEMANTICS) to change `subtypep` to give specialized `array` and `complex` type specifiers the same meaning for purposes of type discrimination as they have for declaration purposes. Of course, this also applies to such type specifiers as `vector` and `simple-array` (see section 4.5).

If A and B are type specifiers (other than `*`, which technically is not a type specifier anyway), then `(array A)` and `(array B)` represent the same type in a given implementation if and only if they denote arrays of the same specialized representation in that implementation; otherwise they are disjoint. To put it another way, they represent the same type if and only if `(upgraded-array-element-type 'A)` and `(upgraded-array-element-type 'B)` are the same type. Therefore

    (subtypep '(array A) '(array B))

is true if and only if `(upgraded-array-element-type 'A)` is the same type as `(upgraded-array-element-type 'B)`.

The `complex` type specifier is treated in a similar but subtly different manner. If A and B are two type specifiers (but not `*`, which technically is not a type specifier anyway), then `(complex A)` and `(complex B)` represent the same type in a given implementation if and only if they refer to complex numbers of the same specialized representation in that implementation; otherwise they are disjoint. Note, however, that there is no function called `make-complex` that allows one to specify a particular element type (then to be upgraded); instead, one must describe specialized complex numbers in terms of the actual types of the parts from which they were constructed. There is no number of type (or rather, representation) `float` as such; there are only numbers of type `single-float`, numbers of type `double-float`, and so on. Therefore we want `(complex single-float)` to be a subtype of `(complex float)`.

The rule, then, is that `(complex A)` and `(complex B)` represent the same type (and otherwise are disjoint) in a given implementation if and only if either the type A is a subtype of B, or `(upgraded-complex-part-type 'A)` and `(upgraded-complex-part-type 'B)` are the same type. In the latter case `(complex A)` and `(complex B)` in fact refer to the same specialized representation. Therefore

    (subtypep '(complex A) '(complex B))

is true if and only if the results of `(upgraded-complex-part-type 'A)` and `(upgraded-complex-part-type 'B)` are the same type.

Under this interpretation

    (subtypep '(complex single-float) '(complex float))

must be true in all implementations; but

    (subtypep '(array single-float) '(array float))

is true only in implementations that do not have a specialized array representation for `single-float` elements distinct from that for `float` elements in general.

Next: Specific Data Type Up: Data Type Predicates Previous: Data Type Predicates