[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
(aside about) visible hash tables
Date: Tue, 17 May 88 10:42:01 EDT
From: rose@Think.COM
Date: Mon, 16 May 88 23:51:57 PDT
From: Jon L White <edsel!jonl@labrea.stanford.edu>
I think you've made a useful observation that there a whole slew of potential
(or real) data types in CLtL for which there is no commonly accepted print
syntax, and for which the #S syntax could be naturally extended to cover.
BYTE-SPECIFIER comes to mind, as well as RANDOM-STATE, PATHNAME, HASH-TABLE,
PACKAGE, READTABLE, STREAM, (compiled) FUNCTION, and non-simple ARRAY and
ARRAY with specialized element-type not among {'bit', 'string-char','T'}.
Having a print function presumes having a dynamically distinguishable
type. If BYTE-SPECIFIER is implemented as an integer, you might have
a read syntax for it, but you couldn't expect it to print that way.
...
Well, you couldn't expect it in all possible universes, but you could in some.
The following technique works for at least some implementations and is provided
only for color in this discussion. The main thrust of your point is, of course,
correct.
In Maclisp, we had the problem that people wanted a read macro #/A which
read in as 65 for use in programs, but the problem is that it didn't pretty
print well. Maclisp only `interned' small fixnums, so I once wrote a facility
that generated uninterned small fixnums by adding 1 to a large fixnum (to get
a fresh FIXNUM cell) and then bashing a small number back into the `cdr' of
the fixnum. Then I filled an array of numbers from 0-127 with small fixnums
whose values were 0-127, respectively, but which were not EQ to the normal
0-127. I could then do
(DEFUN READ-CHAR (STREAM) (ARRAYCALL T THE-CHARS (TYI STREAM)))
(DEFUN CHAR= (CHAR1 CHAR2) (= CHAR1 CHAR2))
(DEFUN CHARACTERP (CHAR)
(AND (FIXNUMP CHAR)
(< -1 CHAR 128)
(EQ (ARRAYCALL T THE-CHARS CHAR) CHAR))) ;Use of EQ is critical
(DEFUN CHAR-CODE (CHAR) (+ CHAR 0))
(DEFUN CODE-CHAR (CHAR) (ARRAYCALL T THE-CHARS CHAR))
...etc.
In this way, an integer could be used to represent a character but the fact
that the data object was a character was still preserved. This allowed me to
extend the pretty printer so that #/A would print as #/A and 65 would print as
65 even though
(LET ((X1 #/A) (X2 65))
(AND (EQ (TYPEP X1) 'FIXNUM)
(EQ (TYPEP X2) 'FIXNUM)
(= X1 X2)))
was true. You just had to be sure that CHARACTERP tests always preceded number
tests and you were all set...
Similarly, one could imagine a particular CL implementation which chose to
implement byte pointers as fixnums (and which did not represent fixnums
immediately) might have done:
(DEFMACRO CACHED-BYTE-SIZE (SIZE POSITION)
;there are -definitely- more time-efficient and GC-efficient ways to do
;this but this gets the abstract idea across just fine.
`(GETHASH (LIST SIZE POSITION) *THE-BYTE-SIZES*))
(DEFUN BYTE (SIZE POSITION)
(OR (CACHED-BYTE SIZE POSITION)
(SETF (CACHED-BYTE SIZE POSITION)
(MAKE-UNIQUE-FIXNUM (BYTE-INTERNAL SIZE POSITION)))))
(DEFUN BYTE-INTERNAL (SIZE POSITION)
...fool around with LOGIOR, ASH, etc...)
(DEFUN MAKE-UNIQUE-FIXNUM (VALUE)
...implementation would vary and would only be possible on systems
which didn't represent fixnums immediately...)