DYNAMIC-EXTENT(3cl) |
Common Lisp Reference |
DYNAMIC-EXTENT(3cl) |
NAME
dynamic-extent – assert that a variable or function will be inaccessible after execution (declaration)
SYNOPSIS
(
dynamic-extent
(
function
)
) |
ARGUMENTS and VALUES
—a variable name.
—a function name.
VALID CONTEXT
declaration
BINDING TYPES AFFECTED
variable, function
DESCRIPTION
In some containing form, , this declaration asserts for each (which need not be bound by ), and for each value that takes on, and for each object that is an otherwise inaccessible part of at any time when becomes the value of , that just after the execution of terminates, is either inaccessible (if established a binding for ) or still an otherwise inaccessible part of the current value of (if did not establish a binding for ). The same relation holds for each , except that the bindings are in the function namespace.
The compiler is permitted to use this information in any way that is appropriate to the implementation and that does not conflict with the semantics of Common Lisp.
dynamic-extent declarations can be free declarations or bound declarations.
The dynamic-extent declaration must not refer to symbol macro or macro bindings. s and s named in a
AFFECTED BY
(none)
EXCEPTIONAL SITUATIONS
(none)
NOTES
The most common optimization is to stack allocate the initial value of the objects named by the s.
It is permissible for an implementation to simply ignore this declaration.
EXAMPLES
Since stack allocation of the initial value entails knowing at the object’s creation time that the object can be stack-allocated, it is not generally useful to make a dynamic-extent declaration for variables which have no lexically apparent initial value. For example, it is probably useful to write:
(
defun
()
(
let
((
(
list
1 2 3
)))
(
declare
(
dynamic-extent
))
))
This would permit those compilers that wish to do so to stack allocate the list held by the local variable . It is permissible, but in practice probably not as useful, to write:
(defun () (declare (dynamic-extent )) )
(defun () ( (list 1 2 3)))
Most compilers would probably not stack allocate the argument to in because it would be a modularity violation for the compiler to assume facts about from within . Only an implementation that was willing to be responsible for recompiling if the definition of changed incompatibly could legitimately stack allocate the list argument to in .
Here is another example:
(declaim (inline ))
(defun () (declare (dynamic-extent )) )
(defun () ( (list 1 2 3)))
(defun ()
(flet (( () (declare (dynamic-extent )) ))
( (list 1 2 3))))
In the previous example, some compilers might determine that optimization was possible and others might not.
A variant of this is the so-called “stack allocated rest list” that can be achieved (in implementations supporting the optimization) by:
(defun (&rest )
(declare (dynamic-extent ))
)
Note that although the initial value of is not explicit, the function is responsible for assembling the list from the passed arguments, so the function can be optimized by the compiler to construct a stack-allocated list instead of a heap-allocated list in implementations that support such.
In the following example,
(let (( (list ’ ’ ’))
( (cons ’ (cons ’ (cons ’ nil)))))
(declare (dynamic-extent ))
)
The otherwise inaccessible parts of conses, and the otherwise inaccessible parts of are three other conses. None of the symbols , , , , , , or nil is an otherwise inaccessible part of or because each is interned and hence accessible by the package (or packages) in which it is interned. However, if a freshly allocated uninterned symbol had been used, it would have been an otherwise inaccessible part of the list which contained it. are three
;; In this example, the implementation is permitted to
;; stack allocate the list that is bound to X.
(let (( (list 1 2 3)))
(declare (dynamic-extent ))
(print )
:)
(1 2 3)
:
;; In this example, the list to be bound to L can be
;; stack-allocated.
(defun ()
(do (( (list ) (cdr )))
((null ))
(declare (dynamic-extent ))
(prin1 (car ))))
( 1 2 3)
123
NIL
;; Some implementations might open-code LIST-ALL-PACKAGES
;; in a way that permits using stack allocation of the list
;; to be bound to L.
(do (( (list-all-packages) (cdr )))
((null ))
(declare (dynamic-extent ))
(let (( (package-name (car ))))
(when (string-search "COMMON-LISP" )
(print ))))
"COMMON-LISP"
"COMMON-LISP-USER"
NIL
;; Some implementations might have the ability to stack
;; allocate rest lists. A declaration such as the following
;; should be a cue to such implementations that
;; stack-allocation of the rest list would be desirable.
(
defun
(
&rest
)
(
declare
(
dynamic-extent
))
(
apply
#’
+
))
(
1 2 3
)
6
(defun ()
;; Computes (RANDOM (+ M 1)) at relative speed of
;; roughly O(N).
;; It may be slow, but with a good compiler at least it
;; doesn’t waste much heap storage. :-}
(let (( (make-array )))
(declare (dynamic-extent ))
(dotimes ()
(declare (dynamic-extent ))
(setf (aref ) (random (+ 1))))
(aref )))
(< ( 5 3) 3) true
The following are in error, since the value of is used outside of its extent:
(length (list (let (( (list 1 2 3))) ; Invalid
(declare (dynamic-extent ))
)))
(progn (let (( (list 1 2 3))) ; Invalid
(declare (dynamic-extent ))
)
nil)
SEE ALSO
declare(3cl)
AUTHOR and COPYRIGHT
Substantial portions of this page are taken from draft proposed American National Standard for Information Systems—Programming Language—Common Lisp, X3J13/94-101R, Version 15.17R, Fri 12-Aug-1994 6:35pm EDT; no copyright indicated.
Additional clarification and comments by Michael Marking <marking@tatanka.com>, http://www.tatanka.com/software/cl-manpages/; alternatively, https://github.com/wakinyantanka/cl-manpages/. Copyright 2017 Michael Marking as both an original and a derivative work.
Licensed under Creative Commons Attribution-NoDerivatives 4.0 International (CC BY-ND 4.0).
This page last revised Sunday 26 February 2017.