[Openmcl-devel] Absolute beginner

Gary Byers gb at clozure.com
Wed Apr 8 12:58:57 PDT 2009

A few things which may or may not be worth adding to Mikel's explanation:

- the term "undeclared free variable" is probably historical, but I
   doubt if anyone remembers the history (I don't.)  A better term might
   be "free variable that's not declared to be SPECIAL".  Variables that're
   declared to be SPECIAL have ... um .. special semantics when they're
   used in binding constructs like LET.  The Common Lisp specification
   doesn't even define the semantics of references or assignments to
   free variables that aren't declared to be SPECIAL, though in most
   implementations those references and assignments will behave the
   same way regardless of whether the variable is declared to be SPECIAL.

   Peter Seibel's book "Practical Common Lisp" is available on line at
   <http://www.gigamonkeys.com/book/> (and is also still available in
   hardcopy form.)  Chapter 6 of that book discusses different types
   of CL variables and their usage and semantics.

- more formally, if we want to pervasively declare a variable to be
   SPECIAL, we'd typically use DEFVAR or DEFPARAMETER.  (These two forms
   have similar effects but differ in whether they allow the initial
   value of the variable to be specified and in how they handle the
   situation where the variable in question already has a value.)

   If we do:

(defparameter *bag* 2)

we both set the global value of the variable named *BAG* to be 2 and
pervasively declare ("DECLAIM") the variable *BAG* to be SPECIAL.

Note that I used leading and trailing asterisks in the name of the
variable.  This convention means absolutely nothing to the compiler
or to any other part of the lisp.  That convention - putting *'s 
around the names of SPECIAL variables - is intended to help the
human reader of the code recognize which variables are SPECIAL and
which aren't.

- the function EVAL in CCL behaves as if it was defined something like:

(defun eval (expression)
   (if (very-simple-expression-p expression)
     (%very-simple-eval expression)
     (funcall (compile nil (list 'lambda () expression)))))

The compiler's generally pickier about minor potential problems in the
code that it sees than the very simple evaluator is and may warn about
those problems in cases where the simple evaluator doesn't notice or
doesn't care.

In the tutorial that you were following, the first SETF happens to
be a very simple expression and it's just handled by the simple
evaluator (which doesn't notice or care that BAG is a free variable
not declared to be SPECIAL.)  The DOTIMES form is not EVAL's idea
of a very simple expression, so it's handled by the compiler, which
does notice and warns about something that in some contexts could
be indicative of a problem.

- the practice of introducing "global but non-SPECIAL" variables
in the REPL with SETF or SETQ (rather than using DEFVAR/DEFPARAMETER)
is arguably a little sloppy but very common, and it's not clear that
warnings for code that's going to be immediately executed are all that
useful (if the problem's severe, you'll likely get an error pretty
soon, and if it isn't, it's probably OK to be a little sloppier in the
REPL than elsewhere.)  The only exception that I can think of involves
cases like:

   (sleep (* 60 60 24 7 2)) ; wait until after vacation

which involves a moral dilemma as well as practical issues: should the
compiler point out that the user's misspelled "meltdown" or not ?)

- once the reasons for the warning become clear to them, it's probably
the case that most people ignore this warning when it occurs in the REPL.
If that's true, then it's probably reasonable for the REPL to ignore
it for them.

On Wed, 8 Apr 2009, mikel evins wrote:

> On Apr 8, 2009, at 10:36 AM, Stephen Ng wrote:
>> Hi!
>> I am going through a tutorial on Lisp using Clozure CL and came across
>> a warning message and wonder if someone can explain it to me -
>> ? (setf bag 2)
>> 2
>> ? (dotimes (x 6) (setf bag (* bag bag)))
>> ;Compiler warnings :
>> ;   In an anonymous lambda form: Undeclared free variable BAG (3
>> references)
>> NIL
>> ? bag
>> 18446744073709551616
> A variable whose definition isn't in the present scope is called a
> "free variable". For example, in
>  (+ 2 j)
> the j is a free variable. We can't tell from looking at that snippet
> alone whether j has a definition. In your example above, bag is a free
> variable. It so happens that in your code everything is fine, because
> you previously used SETF to establish a binding for bag in the
> enclosing scope, but the compiler can't tell that just from looking at
> the expression
>   (dotimes (x 6) (setf bag (* bag bag)))
> Since it can't tell just from looking at that expression whether you
> meant for bag to refer to something that was previously defined
> somewhere else, it warns you about the free variable. It goes ahead
> and compiles the code, and runs it just fine (because it so happened
> that there was an appropriate definition of bag in the enclosing
> scope), but in general the compiler can't know that, and it's pretty
> common that undeclared free variables are actually errors (typos, or
> accidental uses of variables that are out of scope, or other such
> mistakes), so when the compiler encounters you, it warns you before
> continuing, in case there's something you need to fix.
> --me
> _______________________________________________
> Openmcl-devel mailing list
> Openmcl-devel at clozure.com
> http://clozure.com/mailman/listinfo/openmcl-devel

More information about the Openmcl-devel mailing list