From: Bruno Haible
Subject: *print-readably* and hash tables
Date: 
Message-ID: <6h03n4$jv4$1@nz12.rz.uni-karlsruhe.de>
According to ANSI CL, hash tables cannot be relied on being printable
when *print-readably* is true. This is annoying because hash tables
are one of the most frequently used data containers.

I propose to specify an external representation of hash tables.

Example:
  (let ((h (make-hash-table :test #'equal)))
    (setf (gethash 10 h) 'dix)
    (setf (gethash 100 h) 'cent)
    (write-to-string h :readably t))
  ==> "#S(HASH-TABLE EQUAL (100. . CENT) (10. . DIX))"
  or  "#S(HASH-TABLE EQUAL (10. . DIX) (100. . CENT))"

Formal proposal:

(CLHS chapter 22.1.3.)

If *print-readably* is false, any hash table is printed as follows.
The printed representation begins with "#S(", followed by the symbol
HASH-TABLE, followed by space, followed by the symbol denoting the
hash table's test function. Then, for each key/value pair present in
the hash table, come space, "(", the key, space, ".", space, the value
and ")". The order of the key/value pairs does not matter here.
Finally, a ")" is added.

(What is denoted as "space" here, is actually a single space if
*print-pretty* is false, or whitespace if *print-pretty* is true.)

If *print-readably* is true, the hash table is printed in an
implementation-defined manner. If all the keys and all the values in
the hash table can be printed without signalling a PRINT-NOT-READABLE
condition, then the hash table can be printed without signalling a
PRINT-NOT-READABLE condition.

(CLHS chapter 2.4.8.13.)

When reading #s(name slot1 value1 slot2 value2 ...), if name is the
symbol HASH-TABLE, a hash table is read according to the syntax

    #s(HASH-TABLE test (key1 . value1) (key2 . value2) ...)

Examples:

  See above.

Rationale:

  The output purposely looks like an alist.

Current Practice:

  CLISP implements this.

Cost to Implementors:

  Minor.

Cost to Users:

  None.

Cost of non-adoption:

  Hash tables would remain the only container type specified in CL which
  cannot be printed readably.

Performance impact:

  None.

Benefits:

  User code can store hash tables on disk without having to convert them
  to alist or vector representation.

Esthetics:

  Elegant, isn't it?


Bruno <······@clisp.cons.org>                  http://clisp.cons.org/~haible/

From: Kent M Pitman
Subject: Re: *print-readably* and hash tables
Date: 
Message-ID: <sfw4szws4rc.fsf@world.std.com>
······@clisp.cons.org (Bruno Haible) writes:

>   ==> "#S(HASH-TABLE EQUAL (100. . CENT) (10. . DIX))"
>   or  "#S(HASH-TABLE EQUAL (10. . DIX) (100. . CENT))"

I've long advocated that systems use #S notation for other than
just structures, however for conceptual compatibility (and better
extensibility), I'd prefer to see:

 #S(HASH-TABLE :TEST EQUAL :MAPPING ((100. . CENT) (10. . DIX))) 

- - - -

Similarly, you might want to fix arrays with special attributes
similarly to allow:

 #S(ARRAY :FILL-POINTER 0 :CONTENTS (...))

or

 #S(ARRAY :FILL-POINTER 0
          :DISPLACED-TO ...
          :DISPLACED-INDEX-OFFSET 3)

In the case of arrays, the name :initial-contents lis already used
in MAKE-ARRAY, so one imagines there is at least conceptually a "slot"
named CONTENTS which we could regard these operations as exposing.


- - - - -


By the way, under Aesthetics, you might want to treat the issue that
some will prefer (100 CENT) (10 DIX) ...etc.
because it will use less file space and be more readable for people
saving ASCII images.  However, I agree with your decision to propose
dotted pairs since the language prefers that kind of associations
in all its built-in operators.

The way X3J13 handled proposals with "optional variations" was to have
a main proposal followed by several optional "mixin" proposals whose
names started with "+" so that you could vote in your main proposal
and then vote on various options on a pick-and-choose basis.  A basic
proposal such as you've done plus some optional additional proposals
+USE-KEYWORDS and +USE-NONDOTTED-LISTS would be the best way to
capture these alternate variations into a single writeup.

- - - - -

In general, I personally endorse an approach of the genral kind you
suggest; for now, I speak only as an individual and not as a
representative of anything.
From: dan corkill
Subject: Re: *print-readably* and hash tables
Date: 
Message-ID: <3533c587.0@rcfnews.cs.umass.edu>
In article <············@nz12.rz.uni-karlsruhe.de>,
Bruno Haible <······@clisp.cons.org> wrote:
>According to ANSI CL, hash tables cannot be relied on being printable
>when *print-readably* is true. This is annoying because hash tables
>are one of the most frequently used data containers.
>
>I propose to specify an external representation of hash tables.
>
>Example:
>  (let ((h (make-hash-table :test #'equal)))
>    (setf (gethash 10 h) 'dix)
>    (setf (gethash 100 h) 'cent)
>    (write-to-string h :readably t))
>  ==> "#S(HASH-TABLE EQUAL (100. . CENT) (10. . DIX))"
>  or  "#S(HASH-TABLE EQUAL (10. . DIX) (100. . CENT))"
>

In our hash-table printer we also include the size, rehash-size,
and rehash-treshold values with the assumption that they may be
useful when the table is restored.  (We also include the count
as a cross-check and use spread syntax rather than assoc.)  We
debated whether or not to include the "implementational" values,
and decided that they were important.

-- Dan Corkill
   Blackboard Technology