From: David Bakhash
Subject: DEFVAR weirdness
Date: 
Message-ID: <m3snityvvi.fsf@alum.mit.edu>
Hi,

I think it's a bit annoying that you can't add a docstring to a DEFVAR
without first giving it an initial value.  This doesn't make much
sense to me as a constraint.  Is the only way out to just defvar it
without the docstring and then (setf documentation) on it?

dave

From: Kent M Pitman
Subject: Re: DEFVAR weirdness
Date: 
Message-ID: <sfwae50mr3z.fsf@world.std.com>
David Bakhash <·····@alum.mit.edu> writes:

> I think it's a bit annoying that you can't add a docstring to a DEFVAR
> without first giving it an initial value.

Not to detract from your point, which has some validity, but I really think 
unbound "declared variables" are overrated.  Most can tolerate a NIL.

> This doesn't make much sense to me as a constraint.

DEFVAR didn't arise as the output of a multi-year language design effort.
DEFVAR is a hack written by some programmer that got into enough programs
that we decided to make it part of the language because people were using
it as-is.  DEFSTRUCT slot properties have this same problem, for more or
less the same reasons. 

In fairness, it syntax was lamentable, but not as much as if you'd had
to do (DEFVAR *FOO* :INITIAL-VALUE 3) just so you could tell when you
omitted the initial value.

> Is the only way out to just defvar it
> without the docstring and then (setf documentation) on it?

Might be.  At least now you can do that.  (SETF DOCUMENTATION) is a latter
day concept that isn't nearly as old as DEFVAR.

The other way to do it, which is what I do, is:

 (DEFVAR *FOO*
   ;; Keeps track of foos.
   )

Almost nothing uses doc strings anyway, so there's little loss of benefit
for doing this.  Given SETF of DOCUMENTATION, though, you're free to design
your own DEFVAR variant with better syntax.  (If you do come up with
better syntax, btw, I, at leats, will be curious to know what it is...)
From: David Bakhash
Subject: Re: DEFVAR weirdness
Date: 
Message-ID: <m34rv8xjkw.fsf@alum.mit.edu>
>>>>> "kmp" == Kent M Pitman <Kent> writes:

 kmp> David Bakhash <·····@alum.mit.edu> writes:
 >> I think it's a bit annoying that you can't add a docstring to a
 >> DEFVAR without first giving it an initial value.

 kmp> Not to detract from your point, which has some validity, but I
 kmp> really think unbound "declared variables" are overrated.  Most
 kmp> can tolerate a NIL.

I think that this is the 2nd time that you and I have disagreed on
this point.  The last time had to do with threads and variables.

Let me defend my point, as I feel that not binding DEFVAR'd variables
is a good thing in the cases where I use it.

First off, I definitely like docstrings.  They can go away in compiled 
or delivered images.  I think that adding documentation into the
language (beyond comment syntax) is good.

As for my DEFVAR.  I thought about it some more, and decided that if a 
variable is ``global'', but unbound at the top-level, then it's not
something that you intended users (or even API programmers) to use,
and so adding documentation is not nearly as useful as is is the more
common DEFVAR case.

Furthermore, I think that not only will I put the documentation in a
comment, as you suggested, but that I won't even use DEFVAR, but
instead

(declaim (special *x*))

That's more informative.  But now for the justification...

I don't feel it makes sense to give a variable a value if that value
will never be used.  In fact, the unboundedness of the variable says
something.

CLOS chose to leave uninitialized slots unbound as well, and there is
no doubt there where the value is.  It is in a similar way that the
unboundedness of my variable is meaningful.  Forcing a default value
for DEFSTRUCT slots is one of the things that makes me want to use
CLOS as much as possible.

I do see where you're coming from when you consider the case of a
function's return value being meaningless, and you know it will never
be used, you can return (values) instead of, say, NIL, or whatever the
last form returns.  But people rarely worry about it, bothering to add
the final (values) statement.  It might even lead to some kind of
optimization, whereas it's unlikely that the DEFVAR binding to NIL
versus leaving it unbound is inconsequential.

thanks for the feedback.

dave
From: Kent M Pitman
Subject: Re: DEFVAR weirdness
Date: 
Message-ID: <sfwn18zzki2.fsf@world.std.com>
David Bakhash <·····@alum.mit.edu> writes:

> Furthermore, I think that not only will I put the documentation in a
> comment, as you suggested, but that I won't even use DEFVAR, but
> instead
> 
> (declaim (special *x*))
> 
> That's more informative.

Perhaps (declare (special *x*)) in the particular points of interest
would be more perspicuous, I think.  DECLAIM, when the file is loaded,
acts like PROCLAIM, and will affect other files subsequently compiled;
it only has a per-file effect if the file is compiled but not loaded.

> CLOS chose to leave uninitialized slots unbound as well, and there is
> no doubt there where the value is.

CLOS does not allow the removal of the boundness check even in low safety.
I think (though I didn't double-check just now) that regular variables can
have this check removed.  A consequence is that 
 (if *foo* ...)
may get you testing the unbound object (which is probably "true") in low
safety, while
 (if some-slot ...)
will not.  I personally find it better to initialize the variable so as to
have consistent behavior across safety modes.

> It is in a similar way that the
> unboundedness of my variable is meaningful.  Forcing a default value
> for DEFSTRUCT slots is one of the things that makes me want to use
> CLOS as much as possible.

Really? Hmm. I'd forgotten this, probably since I tend to always give
both my standard-class and struct slots explicit default values.
Well, this might have been to allow the more efficient mode of not
checking for boundness (loss of a memory cycle on every reference) in
struct accesses...

> I do see where you're coming from when you consider the case of a
> function's return value being meaningless, and you know it will never
> be used, you can return (values) instead of, say, NIL, or whatever the
> last form returns.  But people rarely worry about it, bothering to add
> the final (values) statement.  It might even lead to some kind of
> optimization, whereas it's unlikely that the DEFVAR binding to NIL
> versus leaving it unbound is inconsequential.

I think my concerns are other than these, though I think these are related.

Btw, I do sometimes leave defvar situations unbound.  I'm not 100% religious
about giving them bindings.  I just wanted to support my claim that giving 
them a value isn't all horrible.
From: Tim Bradshaw
Subject: Re: DEFVAR weirdness
Date: 
Message-ID: <nkjlmoik8nq.fsf@tfeb.org>
David Bakhash <·····@alum.mit.edu> writes:

> 
> As for my DEFVAR.  I thought about it some more, and decided that if a 
> variable is ``global'', but unbound at the top-level, then it's not
> something that you intended users (or even API programmers) to use,
> and so adding documentation is not nearly as useful as is is the more
> common DEFVAR case.
> 

I think that a global variable which is unbound at toplevel isn't
really global.

What you are presumably doing is establishing a binding in some
context which you then want to access or modify within that context.
If that's what you want to do, then I think the appropriate approach
is to declare just the relevent bindings special.  I find this so
useful that I have a syntactic hack to do it: I have a macro which
defines `dynamic states' which are collections of variables which are
specially bound to establish a state.  You do something like:

(define-dynamic-state (with-foo-state accessing-foo-state)
  %foo% %bar%)

And then you can do:

(with-foo-state ((%foo% 1) (%bar% 2))
  ...)

(accessing-foo-state (%foo%)
  ;; must be dynamically within a WITH-FOO-STATE
  ... %foo% ...)

The macros do the special declarations and check that you are only
binding the variables you said you would when you defined them.  It's
not a huge win, but it makes code that does this a bit less mysterious
because there are less random SPECIAL declarations, and it avoids
having to define a whole load of spurious global variables which have
no useful global purpose.

It's somewhere under www.tfeb.org/lisp/hax.html

--tim
From: David Bakhash
Subject: Re: DEFVAR weirdness
Date: 
Message-ID: <m31yqau9i5.fsf@alum.mit.edu>
>>>>> "tb" == Tim Bradshaw <···@tfeb.org> writes:

 tb> David Bakhash <·····@alum.mit.edu> writes:
 >>  As for my DEFVAR.  I thought about it some more, and decided that
 >> if a variable is ``global'', but unbound at the top-level, then
 >> it's not something that you intended users (or even API
 >> programmers) to use, and so adding documentation is not nearly as
 >> useful as is is the more common DEFVAR case.
 >> 

 tb> I think that a global variable which is unbound at toplevel isn't
 tb> really global.

Yeah.  that's what I meant by ``global''.  I guess the only savings is
that you don't have to declare them special in every single LET form
they're in.

dave