emacs.d/clones/lisp/www.cs.cmu.edu/Groups/AI/html/cltl/clm/node43.html

398 lines
19 KiB
HTML
Raw Normal View History

2022-08-26 19:11:35 +02:00
<!DOCTYPE HTML PUBLIC "-//W3O//DTD W3 HTML 2.0//EN">
<!Converted with LaTeX2HTML 0.6.5 (Tue Nov 15 1994) by Nikos Drakos (nikos@cbl.leeds.ac.uk), CBLU, University of Leeds >
<HEAD>
<TITLE>3. Scope and Extent</TITLE>
</HEAD>
<BODY>
<meta name="description" value=" Scope and Extent">
<meta name="keywords" value="clm">
<meta name="resource-type" value="document">
<meta name="distribution" value="global">
<P>
<b>Common Lisp the Language, 2nd Edition</b>
<BR> <HR><A NAME=tex2html2033 HREF="node44.html"><IMG ALIGN=BOTTOM ALT="next" SRC="icons/next_motif.gif"></A> <A NAME=tex2html2031 HREF="clm.html"><IMG ALIGN=BOTTOM ALT="up" SRC="icons/up_motif.gif"></A> <A NAME=tex2html2025 HREF="node42.html"><IMG ALIGN=BOTTOM ALT="previous" SRC="icons/previous_motif.gif"></A> <A NAME=tex2html2035 HREF="node1.html"><IMG ALIGN=BOTTOM ALT="contents" SRC="icons/contents_motif.gif"></A> <A NAME=tex2html2036 HREF="index.html"><IMG ALIGN=BOTTOM ALT="index" SRC="icons/index_motif.gif"></A> <BR>
<B> Next:</B> <A NAME=tex2html2034 HREF="node44.html"> Type Specifiers</A>
<B>Up:</B> <A NAME=tex2html2032 HREF="clm.html">Common Lisp the Language</A>
<B> Previous:</B> <A NAME=tex2html2026 HREF="node42.html"> OverlapInclusion, and </A>
<HR> <P>
<H1><A NAME=SECTION00700000000000000000>3. Scope and Extent</A></H1>
<P>
<A NAME=SCOPE>In</A>
describing various features of the Common Lisp language, the notions of
<i>scope</i> and <i>extent</i> are frequently useful. These notions arise when
some object or construct must be referred to from some distant part of a
program. <i>Scope</i> refers to the spatial or textual region of the
program within which references may occur. <i>Extent</i> refers to the
interval of time during which references may occur.
<P>
As a simple example, consider this program:
<P><pre>
(defun copy-cell (x) (cons (car x) (cdr x)))
</pre><P>
The scope of the parameter named <tt>x</tt> is the body of the <tt>defun</tt> form.
There is no way to refer to this parameter from any other place but within
the body of the <tt>defun</tt>. Similarly, the extent of the parameter <tt>x</tt>
(for any particular call to <tt>copy-cell</tt>) is the interval from the time
the function is invoked to the time it is exited. (In the general case,
the extent of a parameter may last beyond the time of function exit,
but that cannot occur in this simple case.)
<P>
Within Common Lisp, a referenceable entity is <i>established</i> by the execution
of some language construct, and the scope and extent of the entity are
described relative to the construct and the time (during execution of the
construct) at which the entity is established.
For the purposes of this discussion, the term ``entity'' refers not only
to Common Lisp data objects, such as symbols and conses, but also to
variable bindings (both ordinary and special), catchers,
and <tt>go</tt> targets. It is important to distinguish between
an entity and a name for the entity. In a function definition
such as
<P><pre>
(defun foo (x y) (* x (+ y 1)))
</pre><P>
there is a single name, <tt>x</tt>, used to refer to the first parameter
of the procedure whenever it is invoked; however, a new binding
is established on every invocation. A <i>binding</i> is a particular
parameter instance. The value of a reference to the name <tt>x</tt>
depends not only on the scope within which it occurs (the one in
the body of <tt>foo</tt> in the example occurs in the scope of the
function definition's parameters) but also on the particular
binding or instance involved. (In this case, it depends on the
invocation during which
the reference is made). More complicated examples
appear at the end of this chapter.
<P>
There are a few kinds of scope and extent that are particularly useful
in describing Common Lisp:
<UL><LI>
<i>Lexical scope</i>. Here references to the established
entity can occur only within certain program portions that are
lexically (that is, textually) contained within the establishing construct.
Typically the construct will have a part designated the <i>body</i>,
and the scope of all entities established will be (or include) the body.
<P>
Example: the names of parameters to a function normally are lexically scoped.
<P>
<LI>
<i>Indefinite scope</i>. References may occur anywhere, in any program.
<P>
<LI>
<i>Dynamic extent</i>. References may occur at any time in the interval
between establishment of the entity and the explicit disestablishment
of the entity. As a rule, the entity is disestablished when execution
of the establishing construct completes or is otherwise terminated.
Therefore entities with dynamic extent obey a stack-like discipline,
paralleling the nested executions of their establishing constructs.
<P>
Example: the <tt>with-open-file</tt> construct opens a connection to a file
and creates a stream object to represent the connection. The stream object
has indefinite extent, but the connection to the open file has dynamic extent:
when control exits the <tt>with-open-file</tt> construct, either normally
or abnormally, the stream is automatically closed.
<P>
Example: the binding of a ``special'' variable has dynamic extent.
<P>
<LI>
<i>Indefinite extent</i>. The entity continues to exist as long as the
possibility of reference remains. (An implementation is free to
destroy the entity if it can prove that reference to it is no longer possible.
Garbage collection strategies implicitly employ such proofs.)
<P>
Example: most Common Lisp data objects have indefinite extent.
<P>
Example: the bindings of lexically scoped parameters of a function have
indefinite extent. (By contrast, in Algol the bindings of lexically scoped
parameters of a procedure have dynamic extent.)
The function definition
<P><pre>
(defun compose (f g)
#'(lambda (x)
(funcall f (funcall g x))))
</pre><P>
when given two arguments, immediately returns a function as its value.
The parameter bindings for <tt>f</tt> and <tt>g</tt> do not disappear because the
returned function, when called, could still refer to those bindings.
Therefore
<P><pre>
(funcall (compose #'sqrt #'abs) -9.0)
</pre><P>
produces the value <tt>3.0</tt>. (An analogous procedure would not necessarily work
correctly in typical Algol implementations or, for that matter,
in most Lisp dialects.)
</UL>
<P>
In addition to the above terms, it is convenient to define <i>dynamic scope</i>
to mean <i>indefinite scope and dynamic extent</i>. Thus we speak of
``special'' variables as having dynamic scope, or being dynamically scoped,
because they have indefinite scope and dynamic extent: a special variable
can be referred to anywhere as long as its binding is currently
in effect.
<P>
<img align=bottom alt="change_begin" src="gif/change_begin.gif"><br>
The term ``dynamic scope'' is a misnomer. Nevertheless
it is both traditional and useful.
<br><img align=bottom alt="change_end" src="gif/change_end.gif">
<P>
The above definitions do not take into account the possibility of
<i>shadowing</i>. Remote reference of entities is accomplished by using
<i>names</i> of one kind or another. If two entities have the same name,
then the second may shadow the first, in which case an occurrence
of the name will refer to the second and cannot refer to the first.
<P>
In the case of lexical scope,
if two constructs that establish entities
with the same name are textually nested, then references within the inner
construct refer to the entity established by the inner one; the inner one
shadows the outer one. Outside the inner construct but inside the outer one,
references refer to the entity established by the outer construct.
For example:
<P><pre>
(defun test (x z)
(let ((z (* x 2))) (print z))
z)
</pre><P>
The binding of the variable <tt>z</tt> by the <tt>let</tt> construct shadows
the parameter binding for the function <tt>test</tt>. The reference to the
variable <tt>z</tt> in the <tt>print</tt> form refers to the <tt>let</tt> binding.
The reference to <tt>z</tt> at the end of the function refers to the parameter
named <tt>z</tt>.
<P>
In the case of dynamic extent, if the time intervals of two entities
overlap, then one interval will necessarily be nested within the
other one. This is a property of the design of Common Lisp.
<P>
<hr>
<b>Implementation note:</b> Behind the assertion that dynamic extents nest properly
is the assumption that there is only a single program or process.
Common Lisp does not address the problems of multiprogramming
(timesharing) or
multiprocessing (more than one active processor)
within a single Lisp environment. The documentation for
implementations that extend Common Lisp for multiprogramming or
multiprocessing should
be very clear on what modifications are induced by such extensions
to the rules of extent and scope.
Implementors should note that Common Lisp has been carefully designed
to allow special variables to be implemented using either
the ``deep binding'' technique or the ``shallow binding'' technique,
but the two techniques have different semantic
and performance implications for multiprogramming and multiprocessing.
<hr>
<P>
A reference by name to an entity with dynamic extent
will always refer to the entity of that name
that has been most recently established
that has not yet been disestablished.
For example:
<P><pre>
(defun fun1 (x)
(catch 'trap (+ 3 (fun2 x))))
(defun fun2 (y)
(catch 'trap (* 5 (fun3 y))))
(defun fun3 (z)
(throw 'trap z))
</pre><P>
Consider the call <tt>(fun1 7)</tt>. The result will be <tt>10</tt>. At the time
the <tt>throw</tt> is executed, there are two outstanding catchers with the
name <tt>trap</tt>: one established within procedure <tt>fun1</tt>, and the other
within procedure <tt>fun2</tt>. The latter is the more recent, and so the
value <tt>7</tt> is returned from the <tt>catch</tt> form in <tt>fun2</tt>.
Viewed from within <tt>fun3</tt>, the <tt>catch</tt> in <tt>fun2</tt> shadows the one in <tt>fun1</tt>.
Had <tt>fun2</tt>
been defined as
<P><PRE>
(defun fun2 (y)
(catch 'snare (* 5 (fun3 y))))
</PRE><P>
then the two catchers would have different names, and therefore the one
in <tt>fun1</tt> would not be shadowed. The result would then have been <tt>7</tt>.
<P>
As a rule, this book simply speaks of the scope or extent of an entity;
the possibility of shadowing is left implicit.
<P>
The important scope and extent rules in Common Lisp follow:
<UL><LI>
Variable bindings normally have lexical scope and indefinite extent.
</UL>
<P>
<img align=bottom alt="change_begin" src="gif/change_begin.gif"><br>
<UL><LI> Variable bindings for which there is a <tt>dynamic-extent</tt>
declaration also have lexical scope and indefinite extent,
but objects that are the values of such bindings may have
dynamic extent.
(The declaration is the programmer's guarantee that
the program will behave correctly even if certain of the data objects have only
dynamic extent rather than the usual indefinite extent.)
<P>
<LI> Bindings of variable names to symbol macros by
<tt>symbol-macrolet</tt> have lexical scope and indefinite extent.
</UL>
<img align=bottom alt="change_end" src="gif/change_end.gif">
<P>
<UL><LI>
Variable bindings that are declared to be <tt>special</tt> have dynamic scope
(indefinite scope and dynamic extent).
</UL>
<img align=bottom alt="change_begin" src="gif/change_begin.gif"><br>
<P>
<UL><LI> Bindings of function names established, for example, by <tt>flet</tt> and
<tt>labels</tt> have lexical scope and indefinite extent.
<P>
<LI> Bindings of function names for which there is a <tt>dynamic-extent</tt>
declaration also have lexical scope and indefinite extent,
but function objects that are the values of such bindings may have
dynamic extent.
<P>
<LI> Bindings of function names to macros as established by
<tt>macrolet</tt> have lexical scope and indefinite extent.
<P>
<LI> Condition handlers and restarts have dynamic scope
(see chapter <A HREF="node312.html#CONDITION">29</A>).
</UL>
<img align=bottom alt="change_end" src="gif/change_end.gif">
<P>
<UL><LI>
A catcher established by a <tt>catch</tt>
or <tt>unwind-protect</tt> special form has dynamic
scope.
<P>
<LI>
An exit point established by a <tt>block</tt> construct has lexical
scope and dynamic extent. (Such exit points are also established
by <tt>do</tt>, <tt>prog</tt>, and other iteration constructs.)
<P>
<LI>
The <tt>go</tt> targets
established by a <tt>tagbody</tt>, named by the tags in the <tt>tagbody</tt>,
and referred to by <tt>go</tt>
have lexical scope and dynamic extent. (Such <tt>go</tt> targets
may also appear as tags in the bodies of
<tt>do</tt>, <tt>prog</tt>, and other iteration constructs.)
<P>
<LI>
Named constants such as <tt>nil</tt> and <tt>pi</tt> have indefinite
scope and indefinite extent.
</UL>
<P>
The rules of lexical scoping imply that lambda-expressions
appearing in the <tt>function</tt> construct will,
in general, result in ``closures''
over those non-special variables visible to the lambda-expression.
That is, the function represented by a lambda-expression
may refer to any lexically apparent non-special variable and get the
correct value, even if the construct that established the binding
has been exited in the course of execution.
The <tt>compose</tt> example shown earlier in this chapter
provides one illustration of this.
The rules also imply that special variable bindings are not
``closed over'' as they may be in certain other dialects of Lisp.
<P>
Constructs that use lexical scope effectively
generate a new name for each established entity on each execution.
Therefore dynamic shadowing cannot occur (though lexical shadowing may).
This is of particular importance when dynamic extent is involved.
For example:
<P><PRE>
(defun contorted-example (f g x)
(if (= x 0)
(funcall f)
(block here
(+ 5 (contorted-example g
#'(lambda ()
(return-from here 4))
(- x 1))))))
</PRE><P>
Consider the call <tt>(contorted-example nil nil 2)</tt>. This produces
the result <tt>4</tt>. During the course of execution, there are three
calls on <tt>contorted-example</tt>, interleaved with two establishments
of blocks:
<P><PRE>
(contorted-example nil nil 2)
(block here<IMG ALIGN=BOTTOM ALT="" SRC="_24769_tex2html_wrap43885.gif"> ...)
(contorted-example nil #'(lambda () (return-from here<IMG ALIGN=BOTTOM ALT="" SRC="_24769_tex2html_wrap43885.gif"> 4)) 1)
(block here<IMG ALIGN=BOTTOM ALT="" SRC="_24769_tex2html_wrap43891.gif"> ...)
(contorted-example #'(lambda () (return-from here<IMG ALIGN=BOTTOM ALT="" SRC="_24769_tex2html_wrap43885.gif"> 4))
#'(lambda () (return-from here<IMG ALIGN=BOTTOM ALT="" SRC="_24769_tex2html_wrap43891.gif"> 4))
0)
(funcall f)
where f => #'(lambda () (return-from here<IMG ALIGN=BOTTOM ALT="" SRC="_24769_tex2html_wrap43885.gif"> 4))
(return-from here<IMG ALIGN=BOTTOM ALT="" SRC="_24769_tex2html_wrap43885.gif"> 4)
</PRE><P>
At the time the <tt>funcall</tt> is executed
there are two <tt>block</tt> exit points outstanding, each apparently
named <tt>here</tt>. In the trace above, these exit points are distinguished
for expository purposes by subscripts.
The <tt>return-from</tt> form executed as a result of the <tt>funcall</tt>
operation
refers to the <i>outer</i> outstanding exit point
(<tt>here<IMG ALIGN=BOTTOM ALT="" SRC="_24769_tex2html_wrap43885.gif"></tt>), not the
inner one (<tt>here<IMG ALIGN=BOTTOM ALT="" SRC="_24769_tex2html_wrap43891.gif"></tt>).
This is a consequence of the rules of lexical scoping: it
refers to that exit point textually visible at the point of
execution of the <tt>function</tt>
construct (here abbreviated by the <tt>#'</tt> syntax) that resulted
in creation of the function object actually invoked by the <tt>funcall</tt>.
<P>
If, in this example, one were to change the form <tt>(funcall f)</tt> to
<tt>(funcall g)</tt>, then the value of the call <tt>(contorted-example nil nil 2)</tt>
would be <tt>9</tt>. The value would change because the <tt>funcall</tt> would cause the
execution of <tt>(return-from here<IMG ALIGN=BOTTOM ALT="" SRC="_24769_tex2html_wrap43891.gif"> 4)</tt>, thereby causing
a return from the inner exit point (<tt>here<IMG ALIGN=BOTTOM ALT="" SRC="_24769_tex2html_wrap43891.gif"></tt>).
When that occurs, the value <tt>4</tt> is returned from the
middle invocation of <tt>contorted-example</tt>, <tt>5</tt> is added to that
to get <tt>9</tt>, and that value is returned from the outer block
and the outermost call to <tt>contorted-example</tt>. The point
is that the choice of exit point returned from has nothing to do with its
being innermost or outermost; rather,
it depends on the lexical scoping information
that is effectively packaged up with a lambda-expression when the
<tt>function</tt> construct is executed.
<P>
This function <tt>contorted-example</tt> works only because the
function named by <tt>f</tt> is invoked during the extent of the exit point.
Block exit points are like non-special variable bindings in having
lexical scope, but they differ in having dynamic extent rather than indefinite
extent. Once the flow of execution has left the block construct,
the exit point is disestablished. For example:
<P><PRE>
(defun illegal-example ()
(let ((y (block here #'(lambda (z) (return-from here z)))))
(if (numberp y) y (funcall y 5))))
</PRE><P>
One might expect the call <tt>(illegal-example)</tt> to produce <tt>5</tt>
by the following incorrect reasoning:
the <tt>let</tt> statement binds the variable <tt>y</tt> to the
value of the <tt>block</tt> construct; this value is a function resulting
from the lambda-expression. Because <tt>y</tt> is not a number, it is
invoked on the value <tt>5</tt>. The <tt>return-from</tt> should then
return this value from the exit point named <tt>here</tt>, thereby
exiting from the block <i>again</i> and giving <tt>y</tt> the value <tt>5</tt>
which, being a number, is then returned as the value of the call
to <tt>illegal-example</tt>.
<P>
The argument fails only because exit points are defined in Common Lisp
to have dynamic extent. The argument is correct up to the execution
of the <tt>return-from</tt>. The execution of the <tt>return-from</tt> is
an error, however, <i>not</i> because it cannot refer to the exit point,
but because it does correctly refer to an exit point <i>and</i>
that exit point has been disestablished.
<P>
<BR> <HR><A NAME=tex2html2033 HREF="node44.html"><IMG ALIGN=BOTTOM ALT="next" SRC="icons/next_motif.gif"></A> <A NAME=tex2html2031 HREF="clm.html"><IMG ALIGN=BOTTOM ALT="up" SRC="icons/up_motif.gif"></A> <A NAME=tex2html2025 HREF="node42.html"><IMG ALIGN=BOTTOM ALT="previous" SRC="icons/previous_motif.gif"></A> <A NAME=tex2html2035 HREF="node1.html"><IMG ALIGN=BOTTOM ALT="contents" SRC="icons/contents_motif.gif"></A> <A NAME=tex2html2036 HREF="index.html"><IMG ALIGN=BOTTOM ALT="index" SRC="icons/index_motif.gif"></A> <BR>
<B> Next:</B> <A NAME=tex2html2034 HREF="node44.html"> Type Specifiers</A>
<B>Up:</B> <A NAME=tex2html2032 HREF="clm.html">Common Lisp the Language</A>
<B> Previous:</B> <A NAME=tex2html2026 HREF="node42.html"> OverlapInclusion, and </A>
<HR> <P>
<HR>
<P><ADDRESS>
AI.Repository@cs.cmu.edu
</ADDRESS>
</BODY>