guile-devel
[Top][All Lists]
Advanced

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

Re: truth of %nil


From: Mark H Weaver
Subject: Re: truth of %nil
Date: Tue, 7 Jul 2009 07:14:09 -0400

Having thought more about optimizing %nil handling, it occurs to me
that we will also want boolean tests from within lisp to be optimized.

>From lisp, three values are considered to be false: #f, '(), and %nil.
We can use the same bit-masking trick to do these tests quickly if we
make sure that these three values differ in only two bit positions.

Therefore, I suggest that the first four SCM_MAKIFLAG values should be
#f, %nil, '(), and another never-to-be-used value which would also be
considered false by lisp code as a side effect of the masking trick.

In my previous proposal, I made sure to keep SCM_BOOL_F and SCM_BOOL_T
in IFLAG numbers 0 and 1.  If this is important, it could still be
arranged by making the aforementioned two bit positions something
other than the lowest two bits of the IFLAG number, but that would
mean our three lisp-false values would be spread out (e.g. 0/2/4/6).

Therefore, unless someone tells me otherwise, I'm going to assume it's
okay to put SCM_BOOL_F and SCM_BOOL_T in IFLAG numbers 0 and 4.  These
still have the property that SCM_BOOL_F and SCM_BOOL_T differ by only
one bit, and that SCM_BOOL_F is IFLAG number 0, both of which seem
potentially useful.

So, in my new proposal, the first five IFLAGS are as follows:

#define SCM_BOOL_F              SCM_MAKIFLAG (0)
#define SCM_ELISP_NIL           SCM_MAKIFLAG (1)
/* SCM_MAKIFLAG (2) would also be considered "false" by lisp code
 * and therefore should remain unassigned */
#define SCM_EOL                 SCM_MAKIFLAG (3)
#define SCM_BOOL_T              SCM_MAKIFLAG (4)

This numbering has the nice properties that 0 is #f, the first two are
considered false by scheme, and the first four are considered false by
lisp.

[An alternative numbering for which the following macros would also
 work is: ((#f 0) (#t 1) (%nil 2) (unused 4) (() 6)), if it's important
 to keep #f and #t together]

The testing macros would be as follows (these can of course be renamed
if my other pending proposal is rejected):

#define scm_is_false(x)  \
  (((x) & ~(SCM_ELISP_NIL ^ SCM_BOOL_F)) == (SCM_ELISP_NIL & SCM_BOOL_F))
#define scm_is_true(x)  \
  (((x) & ~(SCM_ELISP_NIL ^ SCM_BOOL_F)) != (SCM_ELISP_NIL & SCM_BOOL_F))
#define scm_is_null(x)   \
  (((x) & ~(SCM_ELISP_NIL ^ SCM_EOL))    == (SCM_ELISP_NIL & SCM_EOL))

#define scm_is_false_xxx_assume_not_lisp_nil(x)  ((x) == SCM_BOOL_F)
#define scm_is_true_xxx_assume_not_lisp_nil(x)   ((x) != SCM_BOOL_F)
#define scm_is_null_xxx_assume_not_lisp_nil(x)   ((x) == SCM_EOL)

And the lisp boolean tests would be something like this:

/*
 * Since we know SCM_ELISP_NIL and SCM_BOOL_F differ by exactly one
 * bit, and that SCM_ELISP_NIL and SCM_EOL differ by exactly one bit,
 * and that they of course can't be the same bit (or else SCM_BOOL_F
 * and SCM_EOL be would equal), it follows that SCM_BOOL_F and SCM_EOL
 * differ by exactly two bits, and those are the ones we need to
 * mask out to collapse all three values together.
 */
#define scm_is_lisp_false(x)  \
  (((x) & ~(SCM_BOOL_F ^ SCM_EOL)) == (SCM_BOOL_F & SCM_EOL))
#define scm_is_lisp_true(x)  \
  (((x) & ~(SCM_BOOL_F ^ SCM_EOL)) != (SCM_BOOL_F & SCM_EOL))

What do you think?

Also, you may have noticed that I've been using the term "lisp"
instead of "elisp".  This is because guile may support other lisps in
the future, and they will also need the same %nil handling.  (For that
matter, we could even use %nil to implement an "old scheme" language
which treats '() as false.)  With this in mind, should SCM_ELISP_NIL
be renamed to SCM_LISP_NIL?

Andy: thanks for the warm reception, and I'll answer your questions in
a later email.

  Best regards,
     Mark




reply via email to

[Prev in Thread] Current Thread [Next in Thread]