Declares a variable as special, provides advice to the Common Lisp system, or helps the programmer to optimize code.
The special form declare
behaves computationally as if it is not present (other than to affect the semantics), and is only allowed in certain contexts, such as after the variable list in a let
, do
, defun
and so on.
(Consult the syntax definition of each special form to see if it takes declare
forms and/or documentation strings.)
There are three distinct uses of declare
: one is to declare Lisp variables as "special" (this affects the semantics of the appropriate bindings of the variables), the second is to provide advice to help the Common Lisp system (in reality the compiler) run your Lisp code faster or with more sophisticated debugging options, and the third (using the :explain
declaration) is to help you optimize your code.
If you use declare
to specify types (and so eliminate type-checking for the specified symbols) and then supply the wrong type, you may obtain a "Segmentation Violation". You can check this by interpreting the code (rather than compiling it).
The declare
special form can be used as documented in the Common Lisp HyperSpec as well as with the following extensions:
hcl:special-global
declares that the symbol is never bound.
In SMP LispWorks the compiler signals error if it detects that a symbol declared as hcl:special-global
is bound, and at run time it also signals an error.
In non-SMP LispWorks the compiler gives an error, but there is no run time check. The run time behavior is the same as cl:special
, with all accesses to the symbol in low safety.
hcl:special-global
is very useful, and because of the checks it is reasonably safe. It is useful not only for speed, but also to guard against unintentionally binding variables that should not be bound.
See also defglobal-parameter.
hcl:special-dynamic
declares that the symbol is never accessed outside the dynamic scope of the binding.In high safety code accessing the symbol outside the scope of binding signals an error. In low safety code it may result in unpredictable behavior.
In non-SMP LispWorks the only effect of this declaration is to make all access to the variable low safety.
hcl:special-dynamic
is useful, but because it can lead to unpredictable behavior you need to ensure that you test your program in high safety when you use it.
hcl:special-fast-access
declares that a symbol should be "fast access".
The semantics of the declaration is the same as cl:special
, except that access to the variable is low safety. In addition, the compiler compiles access to the symbol in a way that speeds up the access, but also introduces a tiny reduction in the speed of the whole system. The balance between these effects is not obvious.
It is not obvious where hcl:special-fast-access
is useful. If you can ensure that the symbol is always bound or never bound then hcl:special-dynamic
or hcl:special-global
are certainly better.
hcl:lambda-list
specifies the value to be returned when a programmer asks for the arglist of a function.values
specifies the value to be returned when you ask for a description of the results of a function.hcl:invisible-frame
specifies that calls to this function should not appear in a debugger backtrace.hcl:alias
specifies that calls to this function should be displayed as calls to an alternative function in a debugger backtrace.hcl:lambda-name
declares the name of the surrounding lambda.:explain
controls messages printed by the compiler while it is processing forms.You can also use define-declaration to add your own declarations, which do not affect compilation but are useful for code walkers.
This section documents the hcl:lambda-name
declaration, which declares the name of the surrounding lambda. This declaration is useful only for a lambda that becomes a standalone function, that is lambda forms that are passed to function
.
The dspec of the function that is returned by function
is specified by the second element in the declaration. In the special case when the second element is a two-element list starting with the symbol subfunction
, the dspec is that list with the dspec of the parent function added as a third element. For example, if you have:
(defun my-parent (x)
#'(lambda (y)
(declare (lambda-name (subfunction sub-name)))
(* x y)))
then the dspec of the subfunction that my-parent
returns would be (subfunction sub-name my-parent)
.
hcl:lambda-name
is useful for debugging purposes and does not affect the behavior of the program. There are two different situations when hcl:lambda-name
is useful:
defun
, (that is creating a "top-level" function at load-time). In this case, you should also use def to be able to locate the source. For example, look at the output of
(pprint (macroexpand-1 '(defun func-name ())))
.
(function (lambda ..))
). In this case, you should be using the (subfunction
sub-name)
form above, so the recorded name contains the dspec of the parent function, otherwise the debugger will not be able to find the source from the subfunction.
hcl:lambda-name
will also modify the function name of flet
and labels
, but these already have a name, so this is not often useful.
Naming functions and subfunctions is useful because it makes it easier to understand the flow of control when you see them in a backtrace. For subfunctions, it makes it easier to trace and advise them (see trace and defadvice).
The remainder of this description documents the syntax and use of :explain
declarations.
declaration ::= (:explain option*)
option ::= optionkey | (optionkey optionvalue)
optionkey ::= :none | :variables | :types | :floats | :non-floats | :all-calls | :all-calls-with-arg-types | :calls | :boxing | :print-original-form | :print-expanded-form | :print-length | :print-level
The :explain
declaration controls messages printed by the compiler while it is processing forms. The declaration can be used with proclaim or declaim as a top level form to give it global or file scope. It can also be used at the start of a #'lambda
form or function body to give it the scope of that function. The declaration has unspecified effect when used in other contexts, for example in the body of a let
form.
An :explain
declaration consists of a set of options of the form (
optionkey
optionvalue)
which associates optionvalue with optionkey or optionkey which associates t
with optionkey. By default, all of the optionkeys have an associated value nil
. All optionkeys not specified by a declaration remain unchanged (except for the special action of the :none
optionkey described below).
The optionkey should be one of the following:
Set value associated with all optionkeys to nil
. This turns off all explanations.
If optionvalue is non-nil, list all the variables of each function, specifying whether they are floating point or not.
If optionvalue is non-nil, print information about compiler transformations that depend on declared or deduced type information.
If optionvalue is non-nil, print information about calls to functions that may allocate floats.
If optionvalue is non-nil, print information about calls to functions that may allocate non-float numbers, for example bignums.
If optionvalue is non-nil, print information about calls to normal functions.
If optionvalue is non-nil, print the argument types for calls to normal functions. Must be combined with :all-calls
.
A synonym for :all-calls
.
If optionvalue is non-nil, print information about calls to functions that may allocate numbers, for example floats or bignums.
If optionvalue is non-nil, modifies the :all-calls
, :floats
and :non-floats
explanations to include the original source code form that contains the call.
If optionvalue is non-nil, modifies the :all-calls
, :floats
and :non-floats
explanations to include the macroexpanded source code form that contains the call.
Use the optionvalue as the value of *print-length*
for :all-calls
, :floats
and :non-floats
explanations.
Use the optionvalue as the value of *print-level*
for :all-calls
, :floats
and :non-floats
explanations.
(defun foo (arg)
(declare
(:explain :variables)
(optimize (float 0)))
(let* ((double-arg (coerce arg 'double-float))
(next (+ double-arg 1d0))
(other (* double-arg 1/2)))
(values next other)))
;;- Variables with non-floating point types:
;;- ARG OTHER
;;- Variables with floating point types:
;;- DOUBLE-ARG NEXT
LispWorks User Guide and Reference Manual - 20 Sep 2017