[comp.sys.xerox] defvar under Lyric

fsbrn@BRL.ARPA (Ferd Brundick, VLD/LTTB) (03/21/88)

Haah,

I'm not entirely sure why I'm sending this message, since it's not a
question or a bug report.  I guess I want to share my thoughts and get
some discussion started.

Oh yeah, the topic is the use of defconstant, defparameter, and defvar
in Xerox Common Lisp.

My first exposure to CL was on a Gould running UN*X.  This went along
with the CL paradigm of editing a file full of functions, starting a
fresh CL process, and loading the file into it.  If things got really
bad you could kill the process and start over.  Even if everything
worked perfectly you always started with the same fresh CL image.

As we all know, the environment is much different on a Xerox
workstation.  For one thing, you are always working in the same
virtual memory unless you *like* to perform a "copy vmem" every day.
This has always caused me some problems when I ported a file from the
Gould to the 1109, and as a result my coding habits and styles have
changed.

So much for background.  My pet project uses a file that contains
nothing but "static" or read/only variables.  According to Steele I
should either use defconstant or defparameter to assign the values
(the original Franz version was forced to use plain old setq).  I
intend to do that, but on the Gould it didn't seem to make much
difference.  I should have made them all defconstants because they
never change during a run; I could always edit the file between runs.
Instead I used defvar and it worked fine.

When I got a copy of Lyric and downloaded my program I left all the
declarations as defvars.  Recently a member of my team (who is just
learning CL, and on an 1109) asked me how to store variables.  I
automatically said "defvar" since that's what I was familiar with.
Later the person complained because their program was modifying the
variables (as it should) and they wanted to restart everything.  I
said in that case they should forget def<anything> and initialize all
the variables in the actual code (perhaps in an init function).  This
is what I do in my large program for all the dynamic variables, most
of which are simply set to NIL anyway.

I got curious enough to start poking around with the 3 defs to see how
they behaved in the Xerox environment.  Steele gives guidelines for
their use, but remember, he is assuming a fresh vmem every time you
run a program.  I created a constant, parameter, and var in the CL
executive (not XCL), saved them with MAKEFILE, and performed the same
series of actions on each one.  First I tried to change it with setq,
setf, the original def command again, and SEdit, then I reloaded the
file.  Some of the results were surprising, but after some thought it
all made sense.  For those of you who haven't tried this, here are my
results.  Note: when a comment says "verbosely" it means the exec
displayed "New VARIABLES definition for xxx", while "silently" means
no warning was made about the change.

DEFCONSTANT
1. defconstant from exec.
2. setq from exec failed        -- as expected
3. setf from exec failed        -- as expected
4. defconstant from exec failed -- big surprise, possible bug
5. modified with SEdit and it worked [verbosely]
6. reloaded file and constant changed [verbosely]

DEFPARAMETER
1. defparameter from exec.
2. setq from exec worked [silently]         -- as expected
3. setf from exec worked [silently]         -- as expected
4. defconstant from exec worked [verbosely] -- inconsistent with above
5. modified with SEdit and it worked [verbosely]
6. reloaded file and parameter changed [verbosely]

DEFVAR
1. defvar from exec.
2. setq from exec worked [silently]         -- as expected
3. setf from exec worked [silently]         -- as expected
4. defvar from exec claimed it worked, but eval'ing gave old value
5. SEdit showed new value! claimed it worked, but eval'ing gave first value.
6. reloaded file and it claimed parameter changed, but it didn't
7. ran makunbound and reloaded file; the file's value was used

What does all this mean?  defconstant and defparameter worked the way
Steele said they should (except for defconstant.4).  defvar, on the
other hand, required quite a bit of head scratching.  What it did was
"correct" but very confusing.  If the atom in question is unbound, it
assigns an initial value.  If it already has a value, setq (and setf)
change the current value but don't bother with the defvar, so nothing
happens when you run FILES?.  A second defvar and SEdit both do the
same thing (making defconstant.4 look more like a bug), but they
affect the *next* initial value, not the current value.  This means if
you use SEdit to change a defvar you might think it worked.  FILES?
will know the variable has been changed and the new defvar value will
be stored when you MAKEFILE, but the variable will not be changed until
the next time you load the file *after* running makunbound or by
starting with a fresh vmem.

Here's the discussion part.  Why bother to use defvar in XCL?  In my
project I'm going to use nothing but defconstant and defparameter in
my static variable file; for example, the atom *does.not.pattern* will
use defconstant because it is a fundamental part of the program, while
the version number will be a defparameter because it is frequently
changing.  Truly dynamic variables will be locally bound and setq'd as
required because they must be reinitialized every time the program (or
a subportion of it) is run.

I've heard defvar is similar to Interlisp INITVARS, and defparameter is
like VARS.  I haven't done much with filecoms.  I guess you should use
defvar only in situations where you would use INITVARS, defconstant
when the value changes once a year (or never), and defparameter the
rest of the time.  If a variable changes during a run it should be
initialized by executable code; I think it sounds crude to reload a
file just to change some variables.

I realize that the def constructs apply to global variables.  I've
gone back to my habit of binding variables at the lowest possible
level, declaring them "special", and accessing them through the stack
instead of creating a swamp full of global variables.  Again, this is
much more of a problem in the Xerox environment than on a mainframe
that trashes your workspace when you exit from your Lisp process.

Does anyone have any comments or insights?  I'm sorry if this was
obvious to everyone else (although I have my doubts about that), but
the Release Notes have very little to say on the subject.  All flames
are welcome because it was only 27 degrees this morning :-).

                                        dsw, fferd
                                        Fred S. Brundick
                                        USABRL, APG, MD.
                                        <fsbrn@brl.arpa>

"If it was from the zoo,
 it would have 'Property of the Zoo' stamped on it."

SCHMIDT@SUMEX-AIM.STANFORD.EDU (Christopher Schmidt) (03/22/88)

	I don't agree with the generalization "...that the def
constructs apply to global variables."  DEFVAR proclaims a variable
special (CLtL, p 68.).  Common Lisp lacks a global variable
declaration mechanism (a serious omission, in my opinion), so Xerox
Lisp provides XCL:DEFGLOBALVAR analogous to DEFVAR, that proclaims
variables global instead of special.  (I.e. compiled code uses the
GVAR opcode which is much more efficient than the FVAR opcode.)

	Although your letter spelled out the implications of the following
inequality, I think it bears repeating that
		(DEFVAR FOO 23)
is not equivalent to 
		(PROCLAIM '(SPECIAL FOO))
		(SETQ FOO 23)
because DEFVAR sets FOO only if it is unbound.  By the same token
		(XCL:DEFGLOBALVAR FOO 23)
is not equivalent to 
		(PROCLAIM '(XCL:GLOBAL FOO))
		(SETQ FOO 23)

	People writing portable Common Lisp code must write some ugly
conditional proclamations, I suspect, if they want good performance.
I hope your letter alerts some programmers to the pitfalls of DEFVAR.
[I have little experience writing portable code, personally.]
--Christopher
-------