Features Download

From: Bruno Haible <bruno <at> clisp.org>
Subject: Re: defvar affecting captured closure variables ?
Newsgroups: gmane.lisp.clisp.general
Date: Monday 8th October 2007 22:43:01 UTC (over 11 years ago)
Sam wrote:
> Eli Bendersky wrote:
> > 
> > Consider this code:
> > 
> > (defun printer (val)
> >   (lambda () (format t "~a~%" val)))
> > 
> > (setq printer-of-10 (printer 10))
> > (funcall printer-of-10)
> > 
> > It prints "10" as expected. However, consider this code:
> > 
> > (defvar val 12)
> > (funcall printer-of-10)
> > 
> > It prints 12 !
> this is, of course, not compliant.

You mean, clisp's result are not ANSI CL compliant? Nah. The program
above is not conforming ANSI CL, therefore clisp can produce arbitrary

Why is it not conforming ANSI CL? Because of section Semantic Constraints:

   "All conforming programs must obey the following constraints ...:

    Special proclamations for dynamic variables must be made in the
    compilation environment."

The code shown above has a SPECIAL proclamation for the variable VAL
in the execution environment (before the funcall) but not in the
compilation environment: at the moment the PRINTER function is defined,
is it not known as a SPECIAL variable. Therefore the code is not

The same holds also for macros. Before defining a function that uses a
that macro must have been defined.

> ISTR that this behavior was implemented intentionally to ease 
> interactive development, because "usually" the printer above would be 
> followed by a (forgotten) defvar.

Yes, exactly. When a user compiles a program, the compiler is allowed to
remember the information whether a variable was SPECIAL or not, because
that allows the compiler to generate more efficient code. But in
interpreted code, when the user changes the state of a variable, or
redefines a macro, he does *not* want to re-evaluate all DEFUNs that
use the variable or macro.

ANSI CL gives the implementation freedom regarding interpreted evaluation,
how much it wants to remember / cache, and how much it wants to evaluate
according the current environment, if the environment has changed. clisp
implements "ad-hoc lookup" for variables, but not for macros.

It would be useful to change clisp to take into account changed macro
definitions during the interpretation of function bodies. It currently does
not do so, for efficiency reasons: macro expansion is slow. But with a more
intelligent caching mechanism, this could be remedied. If the interpreted
function would not only cache the function body's expansion but also the
vector of global macros that this expansion depended on, clisp could
decide to throw away the cached macro expansion and redo the expansion
when it sees that a macro's definition has changed.

Test case:
  (defmacro pair (x y) `(cons ,x ,y))
  (defun foo (a b c d) (pair (pair a b) (pair c d)))
  (foo 1 2 3 4) => ((1 . 2) 3 . 4)
  ; user not satisfied with the result
  (defmacro pair (x y) `(list ,x ,y))
  (foo 1 2 3 4) => ((1 2) (3 4))


This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >> http://get.splunk.com/
CD: 4ms