Common Lisp the Language, 2nd Edition
Next: Declaration Specifiers
Up: Declarations
Previous: Declarations
The declare
construct is used for embedding declarations
within executable code. Global declarations and declarations that are
computed by a program are established by the proclaim
construct.
X3J13 voted in June 1989 (PROCLAIM-ETC-IN-COMPILE-FILE) to introduce
the new macro declaim
, which is guaranteed to be recognized
appropriately by the compiler and is often more convenient than
proclaim
for establishing global declarations.
[Special Form]
declare
{
decl-spec
}*
A declare
form is known as a declaration.
Declarations may occur only at the beginning of the bodies of certain
special forms; that is, a declaration may occur only as a statement of
such a special form, and all statements preceding it (if any) must also
be declare
forms (or possibly documentation strings, in
some cases). Declarations may occur in lambda-expressions and in the
forms listed here.
define-setf-method labels
defmacro let
defsetf let*
deftype locally
defun macrolet
do multiple-value-bind
do* prog
do-all-symbols prog*
do-external-symbols with-input-from-string
do-symbols with-open-file
dolist with-open-stream
dotimes with-output-to-string
flet
Notice of correction. In the first edition, the above list
failed to mention the forms define-setf-method
,
with-input-from-string
, with-open-file
,
with-open-stream
, and with-output-to-string
,
even though their individual descriptions in the first edition specified
that declarations may appear in those forms.
X3J13 voted in June 1989 (CONDITION-RESTARTS) to add
with-condition-restarts
and also (DATA-IO) to add
print-unreadable-object
and
with-standard-io-syntax
. The X3J13 vote left it unclear
whether these macros permit declarations to appear at the heads of their
bodies. I believe that was the intent, but this is only my
interpretation.
X3J13 voted in June 1988 (CLOS) to adopt the Common Lisp Object
System, which includes the following additional forms in which
declarations may occur:
defgeneric generic-function
define-method-combination generic-labels
defmethod with-added-methods
generic-flet
Furthermore X3J13 voted in January 1989 (SYMBOL-MACROLET-DECLARE) to allow declarations to occur before the bodies of these forms:
symbol-macrolet with-slots
with-accessors
There are certain aspects peculiar to symbol-macrolet
(and therefore also to with-accessors
and
with-slots
, which expand into uses of
symbol-macrolet
). An error is signaled if a name defined by
symbol-macrolet
is declared special
, and a
type declaration of a name defined by symbol-macrolet
is
equivalent in effect to wrapping a the
form mentioning that
type around the expansion of the defined symbol.
It is an error to attempt to evaluate a declaration. Those special forms that permit declarations to appear perform explicit checks for their presence.
Compatibility note: In MacLisp, declare
is a special form that does nothing but return the symbol
declare
as its result. The MacLisp interpreter knows
nothing about declarations but just blindly evaluates them, effectively
ignoring them. The MacLisp compiler recognizes declarations but
processes them simply by evaluating the subforms of the declaration in
the compilation context. In Common Lisp it is important that both the
interpreter and compiler recognize declarations (especially
special
declarations) and treat them consistently, and so
the rules about the structure and use of declarations have been made
considerably more stringent. The odd tricks played in MacLisp by writing
arbitrary forms to be evaluated within a declare
form are
better done in both MacLisp and Common Lisp by using
eval-when
.
It is permissible for a macro call to expand into a declaration and be recognized as such, provided that the macro call appears where a declaration may legitimately appear. (However, a macro call may not appear in place of a decl-spec.)
X3J13 voted in March 1988 (DECLARE-MACROS) to eliminate the
recognition of a declaration resulting from the expansion of a macro
call. This feature proved to be seldom used and awkward to implement in
interpreters, compilers, and other code-analyzing programs.
Under this change, a declaration is recognized only as such if it
appears explicitly, as a list whose car is the symbol
declare
, in the body of a relevant special form. (Note,
however, that it is still possible for a macro to expand into a call to
the proclaim
function.)
Each decl-spec is a list whose car is a symbol
specifying the kind of declaration to be made. Declarations may be
divided into two classes: those that concern the bindings of variables,
and those that do not. (The special
declaration is the sole
exception: it effectively falls into both classes, as explained below.)
Those that concern variable bindings apply only to the bindings made by
the form at the head of whose body they appear. For example, in
(defun foo (x)
(declare (type float x)) ...
(let ((x 'a)) ...)
...)
the type
declaration applies only to the outer binding
of x
, and not to the binding made in the
let
.
Compatibility note: This represents a difference from MacLisp, in which type declarations are pervasive.
Declarations that do not concern themselves with variable bindings are pervasive, affecting all code in the body of the special form. As an example of a pervasive declaration,
(defun foo (x y) (declare (notinline floor)) ...)
advises that everywhere within the body of foo
the
function floor
should not be open-coded but called as an
out-of-line subroutine.
Some special forms contain pieces of code that, properly speaking, are not part of the body of the special form. Examples of this are initialization forms that provide values for bound variables, and the result forms of iteration constructs. In all cases such additional code is within the scope of any pervasive declarations appearing before the body of the special form. Non-pervasive declarations have no effect on such code, except (of course) in those situations where the code is defined to be within the scope of the variables affected by such non-pervasive declarations. For example:
(defun few (x &optional (y *print-circle*))
(declare (special *print-circle*))
...)
The reference to *print-circle*
in the first line of
this example is special because of the declaration in the second
line.
(defun nonsense (k x z)
(foo z x) ;First call to foo
(let ((j (foo k x)) ;Second call to foo
(x (* k k)))
(declare (inline foo) (special x z))
(foo x j z))) ;Third call to foo
In this rather nonsensical example, the inline
declaration applies to the second and third calls to foo
,
but not to the first one. The special
declaration of
x
causes the let
form to make a special
binding for x
and causes the reference to x
in
the body of the let
to be a special reference. The
reference to x
in the second call to foo
is
also a special reference. The reference to x
in the first
call to foo
is a local reference, not a special one. The
special
declaration of z
causes the reference
to z
in the call to foo
to be a special
reference; it will not refer to the parameter to nonsense
named z
, because that parameter binding has not been
declared to be special
. (The special
declaration of z
does not appear in the body of the
defun
, but in an inner construct, and therefore does not
affect the binding of the parameter.)
X3J13 voted in January 1989 (DECLARATION-SCOPE) to replace the rules
concerning the scope of declarations occurring at the head of a special
form or lambda-expression:
Note that the distinction between pervasive and non-pervasive declarations is eliminated. An important change from the first edition is that ``initialization’’ forms are specifically not included as part of the body under the first rule; on the other hand, in many cases initialization forms may fall within the scope of certain declarations under the second rule.
X3J13 also voted in January 1989 (DECLARE-TYPE-FREE) to change the
interpretation of type
declarations (see section 9.2).
These changes affect the interpretation of some of the examples from the first edition.
(defun foo (x)
(declare (type float x)) ...
(let ((x 'a)) ...)
...)
Under the interpretation approved by X3J13, the type declaration
applies to both bindings of x
. More accurately,
the type declaration is considered to apply to variable references
rather than bindings, and the type declaration refers to every reference
in the body of foo
to a variable named x
, no
matter to what binding it may refer.
(defun foo (x y) (declare (notinline floor)) ...)
This example of the use of notinline
stands unchanged,
but the following slight extension of it would change:
(defun foo (x &optional (y (floor x)))
(declare (notinline floor)) ...)
Under first edition rules, the notinline
declaration
would be considered to apply to the call to floor
in the
initialization form for y
. Under the interpretation
approved by X3J13, the notinline
would not apply
to that particular call to floor
. Instead the user must
write something like
(defun foo (x &optional (y (locally (declare (notinline floor))
(floor x))))
(declare (notinline floor)) ...)
or perhaps
(locally (declare (notinline floor))
(defun foo (x &optional (y (floor x))) ...))
Similarly, the special
declaration in
(defun few (x &optional (y *print-circle*))
(declare (special *print-circle*))
...)
is not considered to apply to the reference in the initialization
form for y
in few
. As for the
nonsense
example,
(defun nonsense (k x z)
(foo z x) ;First call to foo
(let ((j (foo k x)) ;Second call to foo
(x (* k k)))
(declare (inline foo) (special x z))
(foo x j z))) ;Third call to foo
under the interpretation approved by X3J13, the inline
declaration is no longer considered to apply to the second call to
foo
, because it is in an initialization form, which is no
longer considered in the scope of the declaration. Similarly, the
reference to x
in that second call to foo
is
no longer taken to be a special reference, but a local reference to the
second parameter of nonsense
.
[Macro]
locally
{
declaration
}*
{
form
}*
This macro may be used to make local pervasive declarations where
desired. It does not bind any variables and therefore cannot be used
meaningfully for declarations of variable bindings. (Note that the
special
declaration may be used with locally
to pervasively affect references to, rather than bindings of,
variables.) For example:
(locally (declare (inline floor) (notinline car cdr))
(declare (optimize space))
(floor (car x) (cdr y)))
X3J13 voted in January 1989 (RETURN-VALUES-UNSPECIFIED) to specify
that locally
executes the forms as an implicit
progn
and returns the value(s) of the last
form.
X3J13 voted in March 1989 (LOCALLY-TOP-LEVEL) to make
locally
be a special form rather than a macro. It still has
the same syntax.
[Special Form]
locally
{
declaration
}*
{
form
}*
This change was made to accommodate the new compilation model for
top-level forms in a file (see section 25.1). When a
locally
form appears at top level, the forms in its body
are processed as top-level forms. This means that one may, for example,
meaningfully use locally
to wrap declarations around a
defun
or defmacro
form:
(locally
(declare (optimize (safety 3) (space 3) (debug 3) (speed 1)))
(defun foo (x &optional (y (abs x)) (z (sqrt y)))
(bar x y z)))
Without assurance that this works one must write something cumbersome such as
(defun foo (x &optional (y (locally
(declare (optimize (safety 3)
(space 3)
(debug 3)
(speed 1)))
(abs x)))
(z (locally
(declare (optimize (safety 3)
(space 3)
(debug 3)
(speed 1)))
(sqrt y))))
(locally
(declare (optimize (safety 3) (space 3) (debug 3) (speed 1)))
(bar x y z)))
[Function]
proclaim
decl-spec
The function proclaim
takes a decl-spec as its
argument and puts it into effect globally. (Such a global declaration is
called a proclamation.) Because proclaim
is a
function, its argument is always evaluated. This allows a program to
compute a declaration and then put it into effect by calling
proclaim
.
Any variable names mentioned are assumed to refer to the dynamic values of the variable. For example, the proclamation
(proclaim '(type float tolerance))
once executed, specifies that the dynamic value of
tolerance
should always be a floating-point number.
Similarly, any function-names mentioned are assumed to refer to the
global function definition.
A proclamation constitutes a universal declaration, always in force unless locally shadowed. For example,
(proclaim '(inline floor))
advises that floor
should normally be open-coded in-line
by the compiler (but in the situation
(defun foo (x y) (declare (notinline floor)) ...)
it will be compiled out-of-line anyway in the body of
foo
, because of the shadowing local declaration to that
effect).
X3J13 voted in January 1989 (SPECIAL-TYPE-SHADOWING) to clarify that
such shadowing does not occur in the case of type declarations. If there
is a local type declaration for a special variable and there is also a
global proclamation for that same variable, then the value of the
variable within the scope of the local declaration must be a member of
the intersection of the two declared types. This is consistent with the
treatment of nested local type declarations on which X3J13 also voted in
January 1989 (DECLARE-TYPE-FREE) .
As a special case (so to speak), proclaim
treats a
special
decl-spec as applying to all bindings as
well as to all references of the mentioned variables.
Notice of correction. In the first edition, this sentence
referred to a ``special
declaration-form.’’ That
was incorrect; proclaim
accepts only a decl-spec,
not a declaration-form.
For example, after
(proclaim '(special x))
in a function definition such as
(defun example (x) ...)
the parameter x
will be bound as a special (dynamic)
variable rather than as a lexical (static) variable. This facility
should be used with caution. The usual way to define a globally special
variable is with defvar
or defparameter
.
X3J13 voted in June 1989 (PROCLAIM-ETC-IN-COMPILE-FILE) to clarify
that the compiler is not required to treat calls to
proclaim
any differently from the way it treats any other
function call. If a top-level call to proclaim
is to take
effect at compile time, it should be surrounded by an appropriate
eval-when
form. Better yet, the new macro
declaim
may be used instead.
[Macro]
declaim
{
decl-spec
}*
This macro is syntactically like declare
and
semantically like proclaim
. It is an executable form and
may be used anywhere proclaim
may be called. However, each
decl-spec is not evaluated.
If a call to this macro appears at top level in a file being
processed by the file compiler, the proclamations are also made at
compile time. As with other defining macros, it is unspecified whether
or not the compile-time side effects of a declaim
persist
after the file has been compiled (see section 25.1).
Next: Declaration Specifiers
Up: Declarations
Previous: Declarations
AI.Repository@cs.cmu.edu