Reputation: 27
I’m learning Common Lisp, using CCL. I get a warning when I use a global variable locally. Why does CCL provide this functionality? What is the purpose of this?
(setf n 75)
;;;This function works, but gets a warning about
;;;n being an undeclared free variable.
(defun use-global ()
(write n)
)
;;;This function works without warnings.
(defun global-to-local (x)
(write x)
)
(use-global)
(global-to-local n)
Upvotes: 1
Views: 268
Reputation: 58578
The warning provides little value. The variable is bound by a prior top-level assignment, which creates a binding in the global environment making that variable a global variable. It simply being accessed, which is likely what is intended by the programmer.
An unbound variable warning is very valuable when no definition of a variable is seen because it catches misspellings of variable references. But a top-level setf
or setq
should be noticed by the implementation and treated as a definition.
It is useful to have a warning for cases when a variable is defined by a top-level setf
and then later subject to a let
:
(setf n 42)
(let ((n 43)) (func))
Here, it looks like the programmer might be expecting n
to be a special variable, but it wasn't defined that way. func
will see the top level binding of n
which holds 42, and not the lexical n
which holds 43. So there is a good reason to have a diagnostic here. The intent of the code requires n
to have been declared via defvar
or defparameter
, or proclaimed special.
(Of course, we cannot warn about (let ((n 43)) ...)
when no top-level n
has been seen, because this is the usual situation for the vast majority of lexical variables.)
There is a bit of a defect in ANSI Common Lisp in that the section 3.1.2.1.1 Symbols as Forms says that there are only three kinds of variables: dynamic, lexical and constant. A dynamic variable is one that is declared special, and so according to this reasoning, setf
is not enough to create a dynamic variable. However, section 3.1.1.1 clearly spells out that there exists a global environment. Confusingly, it says that it contains bindings that have indefinite extent and scope, and that it contains dynamic variables. But then "dynamic variable" is defined in the glossary as being a variable with a binding in the dynamic environment, and a dynamic environment is defined as containing bindings with "dynamic extent". So that can't be the global environment. You know, that one which 3.1.1.1 says contains dynamic variables!
Anyway, all this ANSI confusion has created the misconception that setf
or setq
cannot create a variable, which lends support to bogus compiler diagnostics.
Upvotes: 2
Reputation: 51501
Setf
and setq
do not introduce new variables, they modify existing ones.
In order to define something like global variables, use defvar
or defparameter
. These are conventionally written with a leading and ending *
, and they are automatically declared globally special. This means that whenever you re-bind them, this binding is in effect for the entire call stack above it, whatever functions you call from there etc..
In your example, the toplevel setf
did not do that, so when compiling the function use-global
, the compiler does not see that n
is meant as such and issues the warning. In correct and idiomatic Common Lisp code, this warning should generally be treated as an error, since it then indicates a misspelling or typo.
Upvotes: 3
Reputation: 11940
Quick googling suggests in Common Lisp is it done as something like:
(defvar *n* 75)
(defun use-global () (write *n*))
(use-global)
Note the asterisk that decorate global names by convention.
Upvotes: 0