[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

T and NIL



OK, folks, the time has come.  We have to decide what Common Lisp is
going to do about the things that have traditionally been called T and
NIL before we go on any farther.  Up until now, we have deferred this
issue in the hope that people's positions would soften and that their
commitment to Common Lisp would increase over time, but we can't leave
this hanging any longer.  Almost any decision would be better than no
decision.

It is clear that this is an issue about which reasonable people can
differ (and about which unreasonable people can also differ).  I think
that most of us, if we were designing a Lisp totally from scratch, would
use something other than the symbols T and NIL as the markers for truth,
falsity, and list-emptiness.  Most of us have written code in which we
try to bind T as a random local, only to be reminded that this is
illegal.  Most of us have been disgusted at the prospect of taking the
CAR and CDR of the symbol NIL, but the advantages of being able to CDR
off the end of a list, in some situations, are undeniable.

On the other hand, the traditional Maclisp solution works, is used in
lots of code, and feels natural to lots of Lisp programmers.  Should we
let mere aesthetics (and arguable aesthetics at that) push us into
changing such a fundamental feature of the language?  At the least, this
requires doing a query-replace over all code being imported from
Maclisp; at worst, it may break things in subtle ways.

What it comes down to is a question of the relative value that each
group places on compatibility versus the desire to fix all of the things
that Maclisp did wrong.  The Lisp Machine people have opted for
compatibility on this issue, and have lots of code and lots of users
committed to the old style.  The VAX NIL people have opted for change,
with the introduction of special empty-list and truth objects.  They too
have working code embodying their decision, and are loathe to change.
The Spice Lisp group has gone with an empty-list object, but uses the
traditional T for truth.

What we need is some solution that is at least minimally acceptable to
all concerned.  It would be a real shame if anyone seceded from the
Common Lisp effort over so silly an issue, especially if all it comes
down to is refusing to do a moby query-replace.  However, in my opinion,
it would be even more of a shame if we left all of this up to the
individual implementors and tried to produce a language manual that
doesn't take a stand one way or the other.  Such a manual is guaranteed
to be confusing, and it is something that Common Lisp would have to live
with for many years, long after the present mixture of people and
projects has become irrelevant.  Either solution, on either of these
issues, is preferable to straddling the fence and having to say that
predicates return some "unspecified value guaranteed to be non-null" or
words to that effect.

On the T issue, the proposals are as follows:

1. Truth is represented by the symbol T, whose only special property is
that its value is permanently bound to T.

2. Truth (and also special input values to certain functions?) is
represented by a special truthity object, not a symbol.  This object is
represented externally as #T, and it presumably evaluates to itself.  In
this proposal, T is just another symbol with no special properties.

2A. Like proposal 2, but the symbol T is permanently bound to #T, so
that existing code with constructs like (RETURN T) doesn't break.

3. Implementors are free to choose between 1 and 2A.  Predicates are
documented as returning something non-null, but it is not specified what
this is.  It is not clear what to do about the T in CASE statements or
as the indicator of a default terminal stream.

I think this case is pretty clear.  As far as I can tell, everyone wants
to go with option 1 except JONL and perhaps some others associated with
VAX NIL, who already have code that uses #T.  Option 2 would allow us to
use T as a normal variable, which would be nice, but would break large
amounts of existing code.  Option 2A would break much less code, but if
T is going to be bound permanently to something, it is hard to see a
good reason not just to bind it to T.  Option 3 is the sort of ugly
compromise I discussed above.

If, as it appears, VAX NIL could be converted to using T with only a day
or so of effort, I think that they should agree to do this.  It would be
best to do this now, before VAX NIL has a large user community.  If there
are deeper issues involved than just having some code and not wanting to
change, a clear explanation of the VAX NIL position would be helpful.

The situation with respect to NIL is more complex.  The proposals are as
follows:

1. Go with the Maclisp solution.  Both "NIL" and "()" read in as the
symbol NIL.  NIL is permanently bound to itself, and is unique among
symbols in that you can take its CAR and CDR, getting NIL in either
case.  In other respects, NIL is a normal symbol: it has a property
list, can be defined as a function (Ugh!) and so on.  SYMBOLP, ATOM, and
NULL of NIL are T; CONSP of NIL is NIL; LISTP of NIL is controversial,
but probably should be T.

2. Go with the solution in the Swiss Cheese edition.  There is a
separate null object, sometimes called "the empty list", that is written
"()".  This object is used by predicates and conditionals to represent
false, and it is also the end-of-list marker.  () evaluates to itself,
and you can take the CAR and CDR of it, getting () in either case.
NULL, ATOM, and LISTP of () are T; CONSP and SYMBOLP of () are ().
Under this proposal, the symbol NIL is a normal symbol in all respects
except that its value is permanently bound to ().

3. Allow implementors to choose either 1 or 2.  For this to work, we
must require that the null object, whatever it is, prints as "()", at
least as an option.  Users must not represent the null object as 'NIL,
though NIL, (), and '() are all OK in contexts that evaluate them.  The
user can count on ATOM and NULL of () to be T, and CONSP of () to be ().
SYMBOLP of () is officailly undefined.  LISTP of () should be defined to
be T, so that one can test for CAR-ability and CDR-ability using this.

VAX NIL and Spice Lisp have gone with option 2; the Lisp Machine people
have stayed with option 1, and have expressed their disinclination to
convert to option 2.  Most of us in the Spice Lisp group were suspicious
of option 2 at first, but accepted it as a political compromise; now the
majority of our group has come to like this scheme, quite apart from
issues of inertia.  I would point out that option 2 breaks very little
existing code, since you can say things like (RETURN NIL) quite freely.
Code written under this scheme looks almost like code written for
Maclisp -- a big effort to change one's style is not necessary.  It is
necessary, however, to go through old code and convert any instances of
'NIL to NIL, and to locate any occurrences of NIL in contexts that
implicitly quote it.  Option 3 is another one of those ugly compromises
that I believe we should avoid.  My own view is that I would prefer
either option 1 or 2, with whatever one-time inconvenience that would
imply for someone, to the long-term confusion of option 3.

I propose that the Lisp Machine people and other proponents of option 1
should carefully consider option 2 and what it would take to convert to
that scheme.  It is not as bad as it looks at first glance.  If you are
willing to convert, that would be the ideal solution.  If not, I can
state that Spice Lisp would be willing to revert to option 1 rather than
cause a major schism; I cannot, of course, speak for the VAX NIL people
or any other groups on this.

Let me repeat that we must decide this issue as soon as possible.  We
have made a lot of progress on the multiple value and sequence issues,
but until we have settled T and NIL, we can hardly claim that the
language specification is stabilizing.  It would be awfully nice to have
this issue more or less settled before we mass-produce the next edition
of the manual.

-- Scott
   --------