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.