Have I got all the comments correct?
The output of the first test should be:
Variable C is not dynamic, value of C is 5
Variable C is not dynamic, value of C is 7
Variable C is not dynamic, value of C is 9
In fg: Variable C is not dynamic, value of C is unknown
In fg: Variable C is not dynamic, value of C is unknown
(defmacro print-dynamic-property (v)
;; This is a helper to display the interesting
;; properties of the variable
`(let ((has-value nil))
;; only dynamic and global environments count in #'boundp
(if (boundp ',v)
(format t "Variable ~a is dynamic, " (symbol-name ',v))
(format t "Variable ~a is not dynamic, " (symbol-name ',v)))
(ignore-errors
(format t "value of ~a is ~s~%"(symbol-name ',v) ,v)
(setf has-value t))
(if (not has-value)
(format t "value of ~a is unknown ~%"(symbol-name ',v )))))
(defun fg ()
;; The point with this function is that c is not lexically bound.
;; This is a referential declaration, but it doesn't seem do any
;; difference but to get rid of "undefined" warnings when I compile
;; it.
(declare (special c))
(format t "In fg: ")
(print-dynamic-property c)
(values))
;;; First test (of the (let...) below)
;;; When special declaration a) and b) are in effect, variable in
;;; function fg called right after b) is 9, variable in last call to
;;; fg is 5
;;; Second test
;;; When only special declaration a) is set, both fgs yield 5 meaning
;;; that (let ((c 9)) does not extend down the stack
;;; Third test
;;; When only special declaration b) is set, first fg yields 9, but in
;;; the second fg, c is not not bound at all
;;; Fourth test
;;; When no special declaration is given, c is not bound in any of the
;;; calls to fg.
;;; Fifth test
;;; When c is just setq'ed, it has value 1 (from setq) both times.
;;; I.e it is dynamic, but not declared special everywhere. (In cmucl
;;; with *top-level-auto-declare* nil), this behaviour is probably
;;; implementation dependent. (that is
;;; star-top-level-auto-declare-star for those of you reading with
;;; gnus). setq on toplevel is undoable with makunbound.
;;; Sixth test
;;; when c is proclaimed special, it is always dynamic and has values
;;; like first test. Try this last, as it is undoable (until a new
;;; image is started)
(let ((c 5))
(declare (ignorable c))
(print-dynamic-property c)
(let ((c 7))
(declare (ignorable c))
;;(declare (special c)) ; a) uncomment this
(print-dynamic-property c)
(let ((c 9))
(declare (ignorable c))
;;(declare (special c)) ; b) uncomment this
(print-dynamic-property c)
(fg))
(fg)))
;;; For fifth test:
(setq c 1)
;;; for sixth test:
(defparameter c 1) ; execute this to check
Here's a shorter demo of special variables:
(defparameter x 'defparameter-x)
(setq y 'toplevel-setq-y)
(setq z 'toplevel-setq-z)
(defun afun (onevar)
(format t "~&~a ~a ~a ~a~%" x y z onevar))
(let ((x 'let-x-1)
(y 'let-y-1)
(z 'let-z-1))
(declare (special y))
(or x y z)
(let ((x 'let-x-2)
(y 'let-y-2)
(z 'let-z-2))
(or x y z)
(afun y)))
The output is:
LET-X-2 LET-Y-1 TOPLEVEL-SETQ-Z LET-Y-2
At the point of the call to afun: X is dynamic and is bound by the
innermost let. Y is special, so the innermost let shadows its value
lexically. Z is lexical.
In afun: X is still dynamic and still has the binding it had at the
call. Y has the dynamic binding it had at the call, but not the
lexical binding. Z is visible lexically from afun at top level scope.
The argument, onevar, is the lexical binding of Y at the call.
As you can see, a special variable is just like a dynamic variable
except that it gets shadowed by lexical bindings.
At the top level, defparameter makes the variable dynamic. If it's
just setq, it's lexical.
The reason for the (or x y z) is to avoid compiler warnings about
unused variables.
Are there any subtle details I missed?
Yeah.
CMUCL gives:
LET-X-2 LET-Y-2 LET-Z-2 LET-Y-2
Thanks for comments.
The result of this example seems to be predictable to me, I am glad to
conclude. I would like to discuss the comments after the example,
noting that I am not quite content with my understandig yet.
Regarding X, I think it is correct to say that it is proclaimed
special, which is done in the defparameter macro. The effect is that
the special declaration is always in effect. The hyperspec also says
"unless shadowed". I think shadowing means both that a symbol in one
package shadows a symbol with the same name in another package, and
that an inner binding takes precedence over an outer binding. So when
there is a let, the new binding takes over, always, but a lexical one
does not extend to functions called from where the lexical binding is
in effect, a special one does. All bindings of X above are special,
and every new let shadows the old one until (in time) you leave the
let.
Y is special in the toplevel, because of setq, and special in the
first let due to the declaration there, but not special in the inner
let, and therefore the value from the inner let is not visible in the
function. ONEVAR is of course from the inner let because it is copied
to the functions parameter list.
Z is special on toplevel, shadowed by the lexical bindings in both
lets, but those lexical bindings are not seen in the function,
therefore the value in the function is the one from the toplevel.
I think this really could be stated even more precise using the terms
scope (where, in the text), a binding is valid, and extent (the
duration in time wherein the binding is valid).
> In article <a6789134.02090...@posting.google.com>,
> cubic...@mailandnews.com (Software Scavenger) wrote:
>
> > The output is:
> > LET-X-2 LET-Y-1 TOPLEVEL-SETQ-Z LET-Y-2
>
> Yeah.
>
> CMUCL gives:
>
> LET-X-2 LET-Y-2 LET-Z-2 LET-Y-2
That is because you have *top-level-auto-declare* set to T
(star-top-level-auto-declare-star) in CMUCL. Then a setq on toplevel
also proclaims the variables special. If you set this to nil, you
should get the same result as Rainer (and me). But you have change the
variable names, or restart the image, because special proclamations
are eternal.
> Rainer Joswig <jos...@lispmachine.de> writes:
>
> > In article <a6789134.02090...@posting.google.com>,
> you should get the same result as Rainer...
Sorry, mixed up the names here.
I am sorry to say that I find your exposition extremely confused, but this
one at least has a simple answer. There is no standard way to remove
special proclamations, but they are associated with a symbol, and there are
at least two ways to get rid of symbols. The function `unintern´ ensures
that the name of the symbol will no longer map to the symbol that has the
special proclamations associated with it. The function `delete-package´
ensures that you can no longer access the package by name, and unless you
have the package as your current package, you should be able to start afresh.
A simple way to ensure that you start off fresh with an experiment (although
I think experimentation to discover how special variables works must fail),
is to create a new package for each run of your experiment and discard it
when you are done.
--
Erik Naggum, Oslo, Norway
Act from reason, and failure makes you rethink and study harder.
Act from faith, and failure makes you blame someone and push harder.
> * Johan Ur Riise
> | But you have change the variable names, or restart the image, because
> | special proclamations are eternal.
>
> I am sorry to say that I find your exposition extremely confused,
> but this one at least has a simple answer. There is no standard
> way to remove special proclamations, but they are associated with
> a symbol, and there are at least two ways to get rid of symbols.
> The function `unintern´ ensures that the name of the symbol will
> no longer map to the symbol that has the special proclamations
> associated with it. The function `delete-package´ ensures that
> you can no longer access the package by name, and unless you have
> the package as your current package, you should be able to start
> afresh.
Thanks, you are of cause right.
> ...(although I think experimentation to discover how special
> variables works must fail)...
I use both the hyperspec and experimenting. Certainly I would stand no
chance at all with the documentation only.
I think you need to examine the reasons for this. I read it to mean that
you have not achieved predictability for what you read in the documentation,
which is a sign that there is some underlying issue or concept that is still
very unclear to you. It is also very hard to help you with something you
struggle with at too high a level, which is the impression I got from reading
your list of experiments, as well.
Perhaps it may be helpful to understand lexical vs special bindings by
examining the situation before, during, and after each form of binding.
First, let us take a lexical binding of the variable `foo´. Suppose first
that `foo´ is not bound. The lexical binding introduces a new variable to
the scope of the binding, which is not accessible by any means outside that
scope, even if you have the name. Because a lexical bindings is unique, a
lexical binding may survive its scope by returning a closure from the scope.
A lexical binding is therefore an object. This will become important soon.
Now, suppose instead that `foo´ was already bound when we entered this scope
where a new variable with an existing name is introduced. The name refers
to the lexically enclosing scope, and there is no way to refer to any other
scope. One may therefore argue that the binding from the outer scope is
shadowed, but it would be equally valid to argue that the object that is the
binding has been pushed on a stack when entering the scope and gets popped
off that stack when exiting the scope, making the name refer to the same
binding it did before the intervening scope. However, since lexical bindings
are inaccessible from without, these binding objects may be compile-time
constructs unless they are closed over by a closure that is passed to other
functions or returned from its scope. Typically, lexical bindings are held
in registers and are shuttled back and forth between memory at will, using a
stack or a predetermined slot in the stack frame and their nature as objects
is only seen when understanding the true nature of closures. An explanation
of their implementation is outside the scope of this discussion, however.
Let us now examine the special binding of the variable `foo´. What makes a
special binding special is that there is only binding object, so it cannot
be captured by a closure. A re-binding of `foo´ must explicitly save and
restore the value of the binding because the single binding object cannot be
replaced by a new object as it is accessible everywhere the name of the
special variable is known. The great value of special variables as global
variables with clearly defined binding behavior instead of the usual setting
behavior in inferior languages, is thus achieved by using the same syntax
for all bindings to cause save and restore to become automatic when the
variable is special and shadowing when the variable is "normal", but through
exactly the same underlying principle of pushing and popping bindings.
Now, what may seem strange, but really is very useful, the variable value of
a symbol /is/ that single binding object for the special variable named by
that symbol. The reason this may confuse people is pretty obvious, though:
There are several ways to reference the value of the single binding of a
special variable. A top-level `(setq foo bar)´ will behave like `(setf
(symbol-value 'foo) bar)´ as this is indeed what the operation actually
amounts to anywhere a special variable is referenced. Therefore, if you do
a top-level `setq´, you exploit a feature in many Common Lisp
implementations where an unknown or "free" variable is assumed to be special
without being pervasively declared to be so. This can come in very handy,
but it is also known to confuse people, so there should probably be a switch
to signal an error in this case to help new users understand what they are
doing. In any case, we have a similar issue with functional arguments,
where the single function-binding of a symbol is inferred when you name the
symbol in a "function context" such as passing a symbol to `funcall´.
A convenience to experienced programmers can become confusing for new
programmers. The ability to reference the single binding object of a special
binding with `symbol-value´ should really be thought of as a low-level access
mechanism that is useful when you wish to develop interpreters for your own
languages. Likewise, `boundp´ answers two questions depending on how much
you know when you ask. If the argument is a symbol you know names a special
variable, you ask it whether the single binding it names has a value, i.e.,
whether an enclosing binding exists for a variable that has no global value.
If the argument is a symbol you know /should/ name a special variable that
would always have a value if some file was loaded, such as by `defvar´, you
know that that has not yet happened. Other than this, I think programmers
should stay away from `boundp´ and `makunbound´ unless they intend to
communicate through the boundness of variables like one may communicate
through the boundness of slots in CLOS instances.
I find special variables and their binding behavior exceptionally intuitive,
so I may have some problems explaining them to someone who has not yet seen
what causes me to find it intuitive, but I believe that thinking of bindings
as objects should be helpful in realizing the deeper nature of variables in
Common Lisp. Understanding variables in C/C++ requires a very different
approach, but, these languages also have binding objects, with the difference
that you can actually refer directly to the binding object through pointer
that has the machine address of the binding, even when it is on the stack.
Of course, this can be a major drag on the efficiency of code that must sync
the value of the binding with the actual storage in memory if its address
has been taken, and the `register´ keyword may be used to inform the
compiler that the address of the binding will never be taken. A Common Lisp
program that uses closures will face similar syncronization needs for the
bindings that are closed over when they may be referenced elsewhere at the
same time, but will normally be able to avoid similar syncronization costs.
I hope this has been helpful.
> I think this really could be stated even more precise using the terms
> scope (where, in the text), a binding is valid, and extent (the
> duration in time wherein the binding is valid).
Yes, and we also need to be clear about other words. What is the
exact difference between a special binding and a dynamic binding? Do
both words sometimes but not always mean exactly the same thing as
each other? And what are the exact rules for when one kind of binding
will shadow another?
I also think we should avoid the word "variable" in this discussion,
except when we're discussing the difference between a variable and a
function. Instead, we should use "binding" to mean either a variable
or a function.
> I think you need to examine the reasons for this. I read it to
> mean that you have not achieved predictability for what you read
> in the documentation, which is a sign that there is some
> underlying issue or concept that is still very unclear to you.
Yes, I cannot yet always be shure what my code does.
> I hope this has been helpful.
Indeed, very helpful.
Johan.
There are two spaces for binding variables: lexical and
global (i.e. special) scopes. Global scope differs from lexical in that
global bindings can be viewed from any point in a program, while
visibility of lexical bindings is limited by textual scope inside binding
form.
LET form is used for creating bindings in lexical scope by default, but
can be used for binding in global/special scope if symbol is declared as
special. For example:
;; Establish binding in lexical scope
(LET (X)
(SETF X 1) X)
;; Establish binding in global scope
(LET (X)
(DECLARE (SPECIAL X)
(SETF X 1) X)
Also the forms (SET 'X Y) and (SETF (SYMBOL-VALUE 'X) Y) always bind
in global scope. So,
(LET ((X 1))
(SET 'X 100)
X) => 1
X => 100
If symbol isn't declared as a special one, then in LET form Lisp will
try to find binding in lexical scope first, and then, if failed, in global
scope.
(SET 'Y 1)
(LET ((Y 2)) Y) => 2
(LET () Y) => 1
;; This last also gives 'Warning: This variable is undefined: Y'
;; under CMUCL
is there any difference between *lexical* and *local* ?
> Can we describe the situation as the following?
>
> There are two spaces for binding variables: lexical and
> global (i.e. special) scopes. Global scope differs from lexical in that
> global bindings can be viewed from any point in a program, while
> visibility of lexical bindings is limited by textual scope inside binding
> form.
>
After looking at Hyperspecs, it seemed to me, that it would be more
correct to use 'dynamic/lexical environments' here instead of
'global(special)/lexical spaces/scopes'.
> is there any difference between *lexical* and *local* ?
Sorry. I'm not sure that I understand you question properly. What does *local*
mean?
no problem.
the commonly used term 'local' in context of programming.
Yes.
A variable can be lexical without being local. A variable can be
local without being lexical.
Example of the first:
(let ((x 1))
(defun print-the-x ()
(format t "X is now ~A~%" x))
(defun inc-the-x (n)
(incf x n)
(values)))
Here, the variable X is lexical but not local.
Example of the second:
(defun inc-and-print (n)
(flet ((print-the-x ()
(declare (special x))
(format t "X is now ~A~%" x)))
(let ((x 5))
(declare (special x))
(incf x n)
(print-the-x))
(let ((x 10))
(declare (special x))
(incf x n)
(print-the-x))
(format t "I'm going to reference X when it's not in scope now:~%")
(print-the-x)))
If this were lexically scoped, all the references to X would refer to
different bindings. Wherever the X is declared special, the
references to X refer to the same binding. But when we get outside
the local scopes of X, where it was bound by the LETs, it becomes
unbound.
--
Fred Gilham gil...@csl.sri.com || "If I thought there was anything at
all in your arguments, I should have to be not only a theist, but an
Episcopalian to boot," he said, after one interchange, reckoning that
since Episcopalianism was, in his book, that than which nothing could
be worse, this was an effective reductio ad absurdum. - J. R. Lucas
> Can we describe the situation as the following?
>
> There are two spaces for binding variables: lexical and
> global (i.e. special) scopes. Global scope differs from lexical in that
> global bindings can be viewed from any point in a program, while
> visibility of lexical bindings is limited by textual scope inside binding
> form.
I have always liked the Background/Analysis section of Jonathan Rees's
failed proposal PROCLAIM-LEXICAL. The proposal didn't pass, and is no
longer needed since the feature he sought can be added by user-code now
that there is DEFINE-SYMBOL-MACRO, but his background explanation of how
variables can be perceived seems still solid to me.
http://world.std.com/~pitman/CL/Issues/proclaim-lexical.html
This will most likely cause further confusion.
| If symbol isn't declared as a special one, then in LET form Lisp will try to
| find binding in lexical scope first, and then, if failed, in global scope.
Such as this, which is just plain wrong.
> Yes, and we also need to be clear about other words. What is the
> exact difference between a special binding and a dynamic binding?
> Do both words sometimes but not always mean exactly the same thing
> as each other?
I don't think there's any difference here. Or perhaps one could say
that in Common Lisp the term `special variable' refers to a variable
that obtains its value by the policy of dynamic binding. Thus the
term `special' applies to variables (which have values, obtained one
way or another) and `dynamic' applies to bindings, which are memory
locations where values are stored.
> And what are the exact rules for when one kind of binding will
> shadow another?
I think you mean ``What are the exact rules for when one binding will
shadow another?''
Clearly this is what distinguishes lexical and special variables.
Lexical variables are bound on the basis of the textual structure of
the program; special variables are bound on the basis of the run-time
call-tree structure of the program.
> I also think we should avoid the word "variable" in this discussion,
> except when we're discussing the difference between a variable and a
> function.
I don't understand why you want to eliminate the term `variable'. A
binding is not a variable. Variables name bindings, allowing one to
access the values the bindings contain.
This is important, since there's no one-to-one mapping between
bindings and variables. Variables can refer to different bindings in
their lifetimes, and different variables can refer to the same
binding.
A lot of this stuff became less shadowed and more visible for me after
reading LAMBDA: THE ULTIMATE DECLARATIVE.
> Instead, we should use "binding" to mean either a variable or a
> function.
This is all turned around. A function is just as much a value as the
number 2. Yes, Common Lisp distinguishes between function bindings
and non-function bindings, but the idea of functions as first class
objects requires them to be conceptually the same.
A thought just occurred to me. There are `anonymous functions', which
are created by LAMBDA. Are there, in some useful form, anonymous
value bindings, that is, non-function bindings that have no name but
where the value can still be obtained in some manner?
--
Fred Gilham gil...@csl.sri.com
REPRODUCTIVE RIGHTS: the right not to reproduce, no matter what else
you do. PLANNED PARENTHOOD: an organization that helps you plan to
avoid becoming a parent.
> * Aleksandr Skobelev
> | There are two spaces for binding variables: lexical and global
> | (i.e. special) scopes.
>
> This will most likely cause further confusion.
>
> | If symbol isn't declared as a special one, then in LET form Lisp will
> | try to find binding in lexical scope first, and then, if failed, in
> | global scope.
>
> Such as this, which is just plain wrong.
Could you elaborate on this in more details, please?
I didn't have an intent to get an absolutely correct description of
variables evaluation mechanism but just a somewhat simplificated model
that able to lit a some light on the topic for a person that is not a
Lisp expert. To speak honestly, I wrote it much for myself, because about
a half of year ago I was sure that I had got in special variables. But
novadays they confuses me again.
But, after looking in HyperSpecs and in proposal that has been mentioned
by Kent Pitman (thank you, Kent, it is very useful), I still don't
understand what 'is just plain wrong' in my message. Well, I admit that
terms used are not absolutely correct. I'd like to offer (again) to
replace 'lexical scope' in my message with 'lexical environment' (and map
this term into the same HyperSpecs' term) and 'global scope' with
'dinamic environment' (and map this term into union of terms 'dinamic
environment' and 'global environment' of HyperSpecs; I think that it is
allowed here, because a global environment like a dinamic one contains
dinamic bindings).
But, of course, I might be wrong. So, I hope, you will help me to
understand in what.
of course i've understood nothing.
for me it looks like its a local variable, with some extensions
mechanisms (e.g. like 'static' in C).
You may want to look at chapter 3 of Common Lisp: The Language for a
more complete discussion of scope and extent. It's available online,
but I'm not sure where offhand.
joelh
CLtL2 is available at
http://www-2.cs.cmu.edu/afs/cs.cmu.edu/project/ai-repository/ai/html/cltl/cltl2.html
Other expositions of dynamic and lexical scoping include, but are not
limited to ;)
* http://c2.com/cgi/wiki?ScopeAndClosures
* Steele, Sussman: The Art of the Interpreter ..., at
http://library.readscheme.org/page1.html
The latter uses Scheme, but only the very basics; so the examples should
be easy to transfer to Common Lisp.
Pascal
I need some motivation to do that.
| I didn't have an intent to get an absolutely correct description of
| variables evaluation mechanism but just a somewhat simplificated model that
| able to lit a some light on the topic for a person that is not a Lisp
| expert.
This is the opposite of motivation for me. Some of us here actually spend a
lot of time trying to get things absolutely correct, only to be met with a
strong desire to get it less than correct and highly confused. This is not
rewarding.
| But, after looking in HyperSpecs and in proposal that has been mentioned by
| Kent Pitman (thank you, Kent, it is very useful), I still don't understand
| what 'is just plain wrong' in my message.
Then you do not understand what you wrote, either.
> If symbol isn't declared as a special one, then in LET form Lisp will try to
> find binding in lexical scope first, and then, if failed, in global scope.
This is not true. It is horribly confused.
| So, I hope, you will help me to understand in what.
I no longer know where you went wrong, so I cannot help you.
They're quite different.
Look at these examples:
(let ((behaves-essentially-as-static 0))
(defun foo ()
(incf behaves-essentially-as-static)))
(defun make-adder (increment)
(lambda (val) (+ val increment)))
(defun test-adder ()
(let ((f1 (make-adder 3))
(f2 (make-adder 7)))
(list (apply f1 2) (apply f2 2) (apply f1 5) (apply f2 5))))
Now try first guessing what these two function calls will return:
(list (foo) (foo) (foo))
(test-adder)
//Ingvar
--
Coffee: Nectar of gods / Aesir-mead of sysadmins / Elixir of life
Typo? I think you meant one of the following alternatives, yes?
(defun test-adder ()
(let ((f1 (make-adder 3))
(f2 (make-adder 7)))
(list (funcall f1 2) (funcall f2 2)
(funcall f1 5) (funcall f2 5))))
(defun test-adder ()
(let ((f1 (make-adder 3))
(f2 (make-adder 7)))
(list (apply f1 2 '()) (apply f2 2 '())
(apply f1 5 '()) (apply f2 5 '()))))
(defun test-adder ()
(let ((f1 (make-adder 3))
(f2 (make-adder 7)))
(list (apply f1 '(2)) (apply f2 '(2))
(apply f1 '(5)) (apply f2 '(5)))))
-Rob
-----
Rob Warnock, PP-ASEL-IA <rp...@rpw3.org>
627 26th Avenue <URL:http://www.rpw3.org/>
San Mateo, CA 94403 (650)572-2607
> Ingvar Mattsson <ing...@cathouse.bofh.se> wrote:
> +---------------
> | (defun test-adder ()
> | (let ((f1 (make-adder 3))
> | (f2 (make-adder 7)))
> | (list (apply f1 2) (apply f2 2) (apply f1 5) (apply f2 5))))
> +---------------
>
> Typo? I think you meant one of the following alternatives, yes?
Yes, I did mean FUNCALL instead of APPLY. *sigh* I should really test
code before posting atricles. For *some* bizarre reason, I actually
started out with FUNCALL and then changed it to APPLY, in a fit of
incredible stupidity.
//Ingvar
--
(defun m (a b) (cond ((or a b) (cons (car a) (m b (cdr a)))) (t ())))