[Ecls-list] turn off auto declares

Juan Jose Garcia Ripoll lisp at arrakis.es
Thu Nov 24 01:02:00 UTC 2005


On Thu, 2005-11-24 at 12:09 +1100, Dean O'Connor wrote:
> I don't know if this is possible, but it would also be great if there 
> was a further option for setq to trip errors only at execution time.

I'd rather not include that on "standard" ECL. SETQ is not really a
function. It is a special form. Adding such option would mean adding a
check for a global flag on many spots by, perhaps, redefining the
ECL_SETQ macro. That would be a real performance hog. As I show below,
however, your problem has a solution using standard Common Lisp plus
some environment magic.

> I my situation, my globals (dynamic specials) are created/bound in a 
> root function and accessed by functions called by that execution path.
> (I am trying to use this method for allowing per thread "globals" on an 
> execution path.)
> 
> For example:
> 
>  > (SETQ EXT:*ACTION-ON-UNDEFINED-VARIABLE* 'ERROR)
> Error
>  > (defun foo ()
>         (let ((*global* 1))
>              (declare (special *global*))
>              (print *global*)
>              (bar)
>              (print *global*)))
> Foo
>  > (defun bar ()
>          (setq *global* 2)
>          (setq undefined-local 3))
> Undefined variable referenced in interpreted code.
> Name: *Global*
> Top level.
>  >>
> 
> Instead, if the defun of bar didn't throw an error, but when foo is 
> called, thus calling bar, only the 2nd setq fails, since at this point
> *global* is bound, whereas undefined-local is not.

The problem is that, even if FOO declares *GLOBAL* to be special,
special declarations only has effect on the function in which it
appears, not on the rest of functions. There is no magic flag that
converts *GLOBAL* suddenly on a special variable, and functions to be
called have no standard way of testing whether *GLOBAL* is a special
variable. Not even in standard Common Lisp.

Only thing I can recommend you is to do something like what I show in
the attached file (foo.lsp), which redefines SETQ. When you load it in
the interpreter, it will complain about the only undefined variable. You
have, however, to use the new SETQ everywhere and ensure that any
DEFVAR/DEFPARAMETER has a value (it is not enough to declare the
variable special: it has to have a value to be detected at run time).

> (load "~/foo")
;;; Loading #P"/home/jlr/foo.lsp"
Tried to assign a value to undefined variable *D*
Broken at EVAL.
MY-LISP>> :q
Top level.

Regards,

Juanjo

-------------- next part --------------
(when (find-package "MY-LISP")
   (delete-package "MY-LISP"))

(defpackage "MY-LISP"
	(:use "COMMON-LISP")
	(:shadow "SETQ"))

(in-package "MY-LISP")

(defun var-declared-in-ecl-env (var env)
   (assoc var (car env)))

(defmacro setq (var value &rest rest &environment env)
   (let (form)
     (setf form
	   (if (or (consp var) (var-declared-in-ecl-env var env))
	       `(cl:setq ,var ,value)
	       `(if (boundp ',var)
		 (cl:setq ,var ,value)
		 (error "Tried to assign a value to undefined variable ~A" ',var))))
     (if rest
	 `(progn ,form (setq , at rest))
	 form)))

(let ((a 2))
  (setq a 2))

(let ((*b* 2))
  (declare (special *b*))
  (setq *b* 2))

(defvar *c* 2)

(setq *c* 2)

(setq *d* 3)


More information about the ecl-devel mailing list