From: Russell Wallace
Subject: Global lexical variables?
Date: 
Message-ID: <d486a9b3-13c2-489e-a552-466f792e5965@y71g2000hsa.googlegroups.com>
A global variable can be declared with defparameter and defvar;
however, this also declares the variable as dynamic, which has far as
I can see is not desirable; it seems clisp doesn't really approve of
it either, going by the warning messages of the following form:

WARNING in REFUTE :
CLAUSES-TABLE is neither declared nor bound,
it will be treated as if it were declared SPECIAL.

Is there any way to just declare an ordinary variable at global scope
without making it dynamic?

From: David Golden
Subject: Re: Global lexical variables?
Date: 
Message-ID: <gecuiu$td5$1@aioe.org>
Russell Wallace wrote:

> A global variable can be declared with defparameter and defvar;
> however, this also declares the variable as dynamic, which has far as
> I can see is not desirable; it seems clisp doesn't really approve of
> it either, going by the warning messages of the following form:
> 
> WARNING in REFUTE :
> CLAUSES-TABLE is neither declared nor bound,
> it will be treated as if it were declared SPECIAL.
> 
> Is there any way to just declare an ordinary variable at global scope
> without making it dynamic?

Yes and no. They're not in the standard directly.

There is, however, a way of emulating lexically scoped globals - without
stepping outside common lisp proper - with symbol-macros.  Usually
referred to as "deflexical" or "deflex" macros.

e.g.  Kent Pitman, 1998, 
Message-ID: <···············@world.std.com>#1/1
http://groups.google.com/group/comp.lang.lisp/msg/740caf30dd637ce8

Rob Warnock, 2003,
Message-ID: <······················@speakeasy.net>
http://groups.google.com/group/comp.lang.lisp/msg/a76aac465c18a0a4?dmode=source
From: Russell Wallace
Subject: Re: Global lexical variables?
Date: 
Message-ID: <b2b39907-5673-4389-b4a4-9a1cc65292b3@d45g2000hsc.googlegroups.com>
On Oct 30, 6:31 pm, David Golden <············@oceanfree.net> wrote:
> Yes and no. They're not in the standard directly.
>
> There is, however, a way of emulating lexically scoped globals - without
> stepping outside common lisp proper - with symbol-macros.  Usually
> referred to as "deflexical" or "deflex" macros.

Thanks! That looks messier than just letting them be dynamic, so I
think I'll just let clisp go ahead and disapprove :-)
From: Thomas A. Russ
Subject: Re: Global lexical variables?
Date: 
Message-ID: <ymimygld9d6.fsf@blackcat.isi.edu>
Russell Wallace <···············@gmail.com> writes:

> On Oct 30, 6:31��pm, David Golden <············@oceanfree.net> wrote:
> > Yes and no. They're not in the standard directly.
> >
> > There is, however, a way of emulating lexically scoped globals - without
> > stepping outside common lisp proper - with symbol-macros. ��Usually
> > referred to as "deflexical" or "deflex" macros.
> 
> Thanks! That looks messier than just letting them be dynamic, so I
> think I'll just let clisp go ahead and disapprove :-)

Um, if you let them be dynamic, then you can get clisp to not complain
by first declaring them with DEFVAR or DEFPARAMETER.  That is normally
what you would want.

What behavior do you anticipate getting from dynamic variables that you
don't want to have?

-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Rob Warnock
Subject: Re: Global lexical variables?
Date: 
Message-ID: <5rKdnYgq47To45fUnZ2dnUVZ_jadnZ2d@speakeasy.net>
David Golden  <············@oceanfree.net> wrote:
+---------------
| Russell Wallace wrote:
| > Is there any way to just declare an ordinary variable at global scope
| > without making it dynamic?
| 
| Yes and no. They're not in the standard directly.
| 
| There is, however, a way of emulating lexically scoped globals - without
| stepping outside common lisp proper - with symbol-macros.  Usually
| referred to as "deflexical" or "deflex" macros.
| 
| e.g.  Kent Pitman, 1998, 
| Message-ID: <···············@world.std.com>#1/1
| http://groups.google.com/group/comp.lang.lisp/msg/740caf30dd637ce8
| 
| Rob Warnock, 2003,
| Message-ID: <······················@speakeasy.net>
| http://groups.google.com/group/comp.lang.lisp/msg/a76aac465c18a0a4?dmode=source
+---------------

And free code here:

    http://rpw3.org/hacks/lisp/deflex.lisp


-Rob

p.s. Note to CMUCL users: CMUCL-19d and earlier had a bug in macro
expansion [routine MACROEXPAND-1, file ".../src/code/eval.lisp"] such
that in some cases [e.g., "INCF FOO", but not just "FOO" or "SETF FOO"]
references to symbol macros that had been shadowed by lexical variables
expanded to the symbol macro expansion instead of refering to the lexical
variable. This bug was fixed in the CVS as of Revision 1.43 2006-12-19.
CMUCL-19e and later versions contain that fix. If you are running
CMUCL-19c or -19d, I posted a patch here on 2006-12-18 in article
<·········································@speakeasy.net>. Or you
can just snarf "eval.lisp" from the -19e source tarball.

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Kaz Kylheku
Subject: Re: Global lexical variables?
Date: 
Message-ID: <20081030131345.727@gmail.com>
On 2008-10-30, Russell Wallace <···············@gmail.com> wrote:
> A global variable can be declared with defparameter and defvar;
> however, this also declares the variable as dynamic, which has far as
> I can see is not desirable;

Of course it's desireable. This is a design decision in the Lisp language; it
didn't just happen by accident.

It's desireable that given

  (defvar *x*)

The symbol *x* is now pervasively special, even if it is locally rebound.

It allows us to do nice things like:

  ;; capture standard output to a string:

  (with-output-to-string (*standard-output*)

    ;; don't have to write
    ;; (declare (special *standard-output*)) here

    (format t "hello~%"))

> it seems clisp doesn't really approve of
> it either, going by the warning messages of the following form:
>
> WARNING in REFUTE :
> CLAUSES-TABLE is neither declared nor bound,
> it will be treated as if it were declared SPECIAL.

The ``it'' that CLISP is not approving of here is that you are trying
to use an undefined variable.  This is not well-defined behavior in Lisp.

> Is there any way to just declare an ordinary variable at global scope
> without making it dynamic?

Not directly, but there are ways to emulate such a thing.

Symbol macros behave like global lexicals. The simplest application is
to create a constant:

  (define-symbol-macro x 42)

This is different from defconstant in that forty-two has not pervasively become
anything. You can still bind x in a lexical scope:

  (let ((x ...)) ...)

In this scope now, x is not a symbol macro, and you are not running into the
error that you are defining a constant.

To emulate a variable rather than a constant, introduce a special variable with
DEFVAR and the like, and then define a symbol macro aliasing for it:

  (defvar *x* 42)

  (define-symbol-macro x *x*)

Of course the variable *x* is dynamic, but you you will never be directly
referring to it as *x* but using the macro alias x. This alias name is not
itself pervasively special.  That is to say:

  (let ((x ...))
    ;; *x* remains what it is, x is lexically bound
    )

Beware that such global lexicals can be very annoying. The CLISP implementation
uses some symbol macros for certain internal variables, which makes it hard to
override the behavior!  For instance:

[1]> system::*foreign-encoding*
#<ENCODING CHARSET:UTF-8 :UNIX>

So you'd think *FOREIGN-ENCODING* is a special variable, right? It follows the
``earmuffs'' convention and everything. 

But if you try:

  (let ((system::*foreign-encoding* (ext:make-encoding ...)))
    ... )

you're in for a surprise; it doesn't work. Why? Because it's a symbol macro
which expands to the function call (SYSTEM::FOREIGN-ENCODING).
You've set up a useless lexical variable.

[2]> (macroexpand 'system::*foreign-encoding*)
(SYSTEM::FOREIGN-ENCODING) ;
T

Annoying! Of course, you can SETF to it. Better yet, you can write a
save-and-restore macro for these types of variables:

  ;; not thread-safe!
  (defmacro save-set-and-restore ((place val) &body body)
    (let ((old-val-sym (gensym)))
      `(let ((,old-val-sym ,place))
         (unwind-protect
	   (progn (setf ,place ,val) 
	          ,@body)
	   (setf ,place ,old-val-sym)))))

Test:

 (macroexpand '(save-set-and-restore (foo bar) a b c)) 

 -> (LET ((#:G3290 FOO))
      (UNWIND-PROTECT (PROGN (SETF FOO BAR) A B C) (SETF FOO #:G3290)))
From: Russell Wallace
Subject: Re: Global lexical variables?
Date: 
Message-ID: <44c2e95e-baa5-4fc4-80ef-28923e30de37@r66g2000hsg.googlegroups.com>
On Oct 30, 8:42 pm, Kaz Kylheku <········@gmail.com> wrote:
> The ``it'' that CLISP is not approving of here is that you are trying
> to use an undefined variable.  This is not well-defined behavior in Lisp.

But I did define it:

(defvar clauses-table
	(make-hash-table
		:test 'equal))

Doesn't that count as a definition?

(Thanks for the explanation about the problems with using global
lexical hacks -- my intuition was right about that, at least :-))
From: Thomas A. Russ
Subject: Re: Global lexical variables?
Date: 
Message-ID: <ymiiqr9d974.fsf@blackcat.isi.edu>
Russell Wallace <···············@gmail.com> writes:

> On Oct 30, 8:42��pm, Kaz Kylheku <········@gmail.com> wrote:
> > The ``it'' that CLISP is not approving of here is that you are trying
> > to use an undefined variable. ��This is not well-defined behavior in Lisp.
> 
> But I did define it:
> 
> (defvar clauses-table
> 	(make-hash-table
> 		:test 'equal))
> 
> Doesn't that count as a definition?

Well, that certainly should count.
But where is this definition in relation to the REFUTE function, since
that is where CLISP was complaining in your earlier post.

Oh, and by the way, it would be good for you to adopt the special
variable naming convention.  It makes the meaning clearer:

(defvar *clauses-table* ...)


-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Russell Wallace
Subject: Re: Global lexical variables?
Date: 
Message-ID: <0dbfcb63-7105-442f-8617-d9666ed6c3d5@u18g2000pro.googlegroups.com>
On Oct 30, 10:11 pm, ····@sevak.isi.edu (Thomas A. Russ) wrote:
> Well, that certainly should count.
> But where is this definition in relation to the REFUTE function, since
> that is where CLISP was complaining in your earlier post.

Turns out it was later than the function definition, rearranging them
fixed it. Thanks!

> Oh, and by the way, it would be good for you to adopt the special
> variable naming convention.  It makes the meaning clearer:
>
> (defvar *clauses-table* ...)

Yeah, maybe you're right.
From: Kaz Kylheku
Subject: Re: Global lexical variables?
Date: 
Message-ID: <20081030173514.753@gmail.com>
On 2008-10-30, Russell Wallace <···············@gmail.com> wrote:
> On Oct 30, 8:42�pm, Kaz Kylheku <········@gmail.com> wrote:
>> The ``it'' that CLISP is not approving of here is that you are trying
>> to use an undefined variable. �This is not well-defined behavior in Lisp.
>
> But I did define it:
>
> (defvar clauses-table
> 	(make-hash-table
> 		:test 'equal))
>
> Doesn't that count as a definition?

It does. I see now that it's only a compiler warning you are getting, while
compiling a particular function.

This means that the definition has not been seen at the time when the compiler
is processing the function.

If the definition is in another file, it means that the file hasn't been
loaded yet.

If the definition is in the same file, the warning means that it's later in the
file than the reference. Thus at the point of reference, the variable isn't
known yet.

The compiler is then only guessing that this free variable will later be
defined as special, and is compiling the reference that way.

A diagnostic is useful, because the compiler is guessing. Maybe you didn't
intend for the reference to be a special variable. Suppose you made this
mistake:

 (defun my-func ()
   foo)

 (define-symbol-macro foo ...) ;; oops, later than reference

Right?

You will run into this error when you have a program made of several modules,
which define some special variables, and there is a circular dependency: module
A uses B's global variable, and B uses A's global variable.

In both possible orders, someone is compiled without the DEFVAR.

One way out of that is to put important global variables into a separate file
dedicated to global variables.

Also, DEFVAR with no value can be used as a forward reference in resolving
these situations. It will ensure that the variable exists, without changing its
value.