Conditions and *PRINT-READABLY*

Pascal J. Bourguignon pjb at informatimago.com
Mon Sep 7 04:54:47 UTC 2015


On 07/09/15 03:47, Steve Haflich wrote:
 > The dictionary page for *print-readably* says
 >
 >    Individual methods for print-object, including user-defined
 >    methods, are responsible for implementing these requirements.
 >
 > so the implementation's applicable print-object method for class
 > condition violates this requirement.

I don't see how:

$ clall -r  '(let ((*print-readably* t))  (prin1-to-string 
(make-condition (quote condition))))'

Armed Bear Common Lisp         #<CONDITION {712BEB60}> cannot be printed 
readably.
Clozure Common Lisp            Attempt to print object #<CONDITION 
#x302000568F2D> on stream #<STRING-OUTPUT-STREAM  :CLOSED #x302000568CFD> .
CLISP                          PRINT: Despite *PRINT-READABLY*, 
#<CONDITION #x0000000200233599> cannot be printed readably.
ECL                            Cannot print object #<a CONDITION> readably.
SBCL                           #<CONDITION {10047AF7D3}> cannot be 
printed readably.

Perfectly conforming.

 > The explanation of *print-readably* unwritten in the ANS is that
 > it's purpose is to provide a guarantee that something written will
 > later be rereadable without error, producing an object that is the
 > "same" as the original.  (The definition of "same" is a different
 > Lisp execution complicated, but not the central focus here.)  Mostly
 > *print-readably* guarantees that the emitted sequence of character
 > can be reread without signalling error.
 >
 > All this depends on a bunch of other assumptions, and the necessary
 > details are incomplete in the ANS.  Here are just some of the
 > issues:
 >
 > What about *print-pretty* and dispatches defined in the current
 > pprint-dispatch?  If there is some such dispatch that would violate
 > rereadability, should the printer ignore that *print-pretty* is
 > true?  A naive reading of the standard suggests this is a
 > requirement (despite being operationally ridiculous) but perhaps the
 > intention was that *print-readably* ought just bind *print-pretty*
 > false.  But if so, the ANS would have said so.

A few variables used by the pretty printer are specified to be set to
NIL when printing readably, but otherwise, it's assumed the pretty
printer will only change the new lines and indentation, not the actual
graphic characters printed.  Using a pretty printer dispatch table
that would change what is printed has not been envisioned in the
specification of *print-readably*.

 > What about other printer variables?  One might define a print-object
 > method that assumes that *print-base* will be the same at reread
 > time -- but the ANS doesn't say this.

Definitely.  Since we cannot assume a *read-base*, integers shall get
the decimal dot when printing readably, or shall be printed with #o,
#b #x or #r.

 > There are a great many more potential issues.  We must conclude that
 > *print-readably* is only a hook for user code to provide a _weak_
 > guarantee that no _other_ user code will do things that prevent
 > printed output from being rereadable without likely notification at
 > write time.  But to achieve even this weak guarantee, user code must
 > cooperate with what it knows about the printer and reader.  That it
 > applies to the printer representation of conditions might protect a
 > mostly-numeric output file from containing an unreadable
 > #<floating-point-underflow> object where a float is expected.

And since we cannot assume a *read-floating-point-format*, printing
readably floating points should not use E or leave it implicit, but
the specific floating point type markers, S, F, D and L. Only clisp
prints numbers readably.

In any case, it cannot ensure either that the floating point types
will have the required precision or more importantly, exponent ranges.
Even clisp will gladly print long floats with more precision that what
could be configured or could exist in the reading context.


 > Perhaps the ANS missed requiring that *print-readably* can assume
 > the emitted sexpr will be reread inside a with-standard-io-syntax?
 > But the ANS doesn't say this.
 >
 > What about the package system?  Whether the printed representation
 > of a symbol has zero, one, or two colons depends on the current
 > state of the package system.  Should *print-readably* assume the
 > package system will be the same at read time? Perhaps, but the ANS
 > doesn't say this.  And with-standard-io-syntax doesn't help with
 > this.

clhs *print-readably* is rather clear:

     If *print-readably* is true, some special rules for printing
     objects go into effect. Specifically, printing any object O1
     produces a printed representation that, when seen by the Lisp
     reader while the standard readtable is in effect, will produce an
     object O2 that is similar to O1. The printed representation
     produced might or might not be the same as the printed
     representation produced when *print-readably* is false. If
     printing an object readably is not possible, an error of type
     print-not-readable is signaled rather than using a syntax (e.g.,
     the ``#<'' syntax) that would not be readable by the same
     implementation. If the value of some other printer control
     variable is such that these requirements would be violated, the
     value of that other variable is ignored.

     Specifically, if *print-readably* is true, printing proceeds as if
     *print-escape*, *print-array*, and *print-gensym* were also true,
     and as if *print-length*, *print-level*, and *print-lines* were
     false.

     If *print-readably* is false, the normal rules for printing and
     the normal interpretations of other printer control variables are
     in effect.

     Individual methods for print-object, including user-defined
     methods, are responsible for implementing these requirements.

     If *read-eval* is false and *print-readably* is true, any such
     method that would output a reference to the ``#.'' reader macro
     will either output something else or will signal an error (as
     described above).


Notice that nothing is said about reading back the representation
without error.  This cannot be ensured, and therefore this is not
specified.

Nothing is said of *package* or with-standard-io-syntax, only the
standard READTABLE is specified for the context of reading back the
representation output.  Also, check the note about *read-eval*.

So you don't have to escape unconditionnally the symbols to print
readably, but you have to qualify them with their packages. All
implementations but clisp will just assume *package* won't change.

$ clall -r  '(make-package "U")' '(let ((*print-readably* t))  
(prin1-to-string (quote (a u::b :c 42 1.2s3 1.2f3 1.2d3 1.2l3))))'

Armed Bear Common Lisp         --> "(A U::B :C 42 1200.0f0 1200.0f0 
1200.0d0 1200.0d0)"
Clozure Common Lisp            --> "(A U::B :C 42 1200.0 1200.0 1200.0D0 
1200.0D0)"
CLISP                          --> "(|COM.INFORMATIMAGO.CLALL|::|A| 
|U|::|B| :|C| 42. 1200.0s0 1200.0f0 1200.0d0 1200.0L0)"
ECL                            --> "(A U::B :C 42 1200.0 1200.0 1200.0d0 
1200.0l0)"
SBCL                           --> "(A U::B :C 42 1200.0 1200.0 1200.0d0 
1200.0d0)"




$ clall -r  '(make-package "U")' '(let ((*print-case* :downcase) 
(*print-readably* t))  (prin1-to-string (quote (a u::b :c 42 1.2s3 1.2f3 
1.2d3 1.2l3))))'

Armed Bear Common Lisp         --> #<PACKAGE U>
Armed Bear Common Lisp         --> "(|COM.INFORMATIMAGO.CLALL|::|A| 
|U|::|B| :|C| 42 1200.0f0 1200.0f0 1200.0d0 1200.0d0)"
Clozure Common Lisp            --> "(a u::b :c 42 1200.0 1200.0 1200.0D0 
1200.0D0)"
CLISP                          --> "(|COM.INFORMATIMAGO.CLALL|::|A| 
|U|::|B| :|C| 42. 1200.0s0 1200.0f0 1200.0d0 1200.0L0)"
ECL                            --> "(a u::b :c 42 1200.0 1200.0 1200.0d0 
1200.0l0)"
SBCL                           --> "(a u::b :c 42 1200.0 1200.0 1200.0d0 
1200.0d0)"


Also note how ABCL switches to qualifying the symbol when *print-case*
is not :upcase anymore :-)



But printing atoms is usually performed by CL functions, called from
the user PRINT-OBJECT methods. Your PRINT-OBJECT methods should just
ensure that it prints readably user objects, and you can defer to CL
the processing of the lisp types.

-- 
__Pascal J. Bourguignon__
http://www.informatimago.com/




More information about the pro mailing list