[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Clarifications please
Date: Thu, 28 Apr 88 18:41:40 EDT
From: James J. Hunt <jjh at ll-vlsi.arpa>
Suppose that I have some variable *GLOBAL* that I need to
dynamically bind for some group of procedures: p1, p2, ... pn.
Furthermore I know that none of these will be called before I
execute some function that binds *GLOBAL*'s value. BIND insists
that *GLOBAL* has a value BEFORE BIND of *GLOBAL* is used. However
some other module may care about *GLOBAL*'s default value, so I
would rather not write something like (lset *GLOBAL* nil), but
instead (if (bound? *GLOBAL*) (then (lset *GLOBAL* nil))). Of
course, I would rather that BIND did not depend on *GLOBAL* being
bound.
I should apologize about BIND's misleading name -- it doesn't bind the
variable (like DEFINE, LAMBDA, and LSET do), it does a temporary assignment.
The variable must be bound (with DEFINE or LAMBDA or LSET) before you
can do a BIND, since otherwise there would be no location to assign.
(Locations can't be created on demand because there's no way to tell in
what environment the variable should become bound.)
However I think it would be a good idea to have a way to bind a variable
without assigning it. MIT Scheme does this with the syntax
(define foo)
and in T this would want to be written as
(lset foo)
instead (because SET!, and therefore BIND, is in principle illegal on
variables bound with DEFINE -- an unfortunate incompatibility with R^3
Scheme).
I know that the SETQ-IF-UNBOUND or DEFVAR style you describe is
widespread in Maclisp and its derivatives. (The special form you want
in T is not BOUND? but rather ASSIGNED?.) But I have always found this
to be a rather questionable practice -- I always prefer for one
particular module to be responsible for binding a variable; i.e.
multiple LSET's on a variable should be in error just as multiple
DEFINE's are. Otherwise conflicts and confusion are very likely.
Likewise, (if (test) (then ...) (else ...))
seems to me much more readable than
(cond ((test) ...) (else ...)).
De gustibus non est disputandum. I needn't add to the existing
critiques. If you like your IF, define a macro.
1. It seem rather ugly to have to use two tables to keep track of
TABLE-HAS-ENTRY? state and the table values, as is need if you
don't plan to modify the source, and
No, you don't need two tables, you just need some distinguished object to
represent a false entry. And you needn't modify the source if you
simply shadow T's definition of TABLE-ENTRY.
2. (walk-table (lambda (key value)
(ignore value)
(set (table-entry <table> key) '#f))
<table>)
does not work. You must say (clean-table <table>). Whereas
this walk does work so long as you are not setting the table
value to '#f. This seems to be a gross anomaly! This is
especially painfull if the new value is computed from the old
one.
I consulted with the person who wrote the table package and it seems
that it's an error to modify a table while it is being walked. That it
sometimes works is gratuitous. Unfortunately it would be prohibitively
expensive to detect this error situation; tables must be fast. And to
change this would require that WALK-TABLE in effect copy the table
before it starts walking; that would make WALK-TABLE too expensive.
This restriction should definitely be documented.
I recommend that you create a brand new table when you want to do
something like this, and let the old one be gc'ed.