From: Kent M Pitman
Subject: Re: princ & *print-readably*
Date: 
Message-ID: <sfwlntzpx9u.fsf@world.std.com>
Sam Steingold <···@usa.net> writes:

> what should (let ((*print-readably* t)) (princ "zz"))
> print? "zz" or zz?
> ACL says zz, CMU says "zz", and CLISP said "zz" untill the today's patch
> wich changed this to zz. Who is right?

Remember that Lisp is somewhat schizo about the use of the names print
and prin1.   PRINT-OBJECT, for example, implements PRIN1, not PRINT.

PRIN1 is only so-called for ancient reasons.  It ought to have been named
PRINT and PRINT should have been named PRINT-ON-OWN-LINE or something.
But for reasons of history and compatibility, it wasn't.

*PRINT-READABLY* is best understood as *PRIN1-READABLY*.  Its role in life
is to bridge the gap between the fact that many things have a printed
representation that is re-readble, but many do not.  In particular,
hash tables, streams, etc. are not re-readable.  So there is nothing
more annoying than writing a program that does


 (DEFUN SAVE-ALL-MY-DATA-FOR-TOMORROW (FILE)
   (WITH-OPEN-FILE (STREAM FILE :DIRECTION :OUTPUT)
     (PRINT *ALL-MY-DATA* STREAM)))

only to find out  what was saved to a file was

  (FOO BAR ...)

or

  (FOO BAR #<STREAM ...>)

because tomorrow when I'm going to do

 (DEFUN READ-ALL-MY-DATA (FILE)
   (WITH-OPEN-FILE (STREAM FILE :DIRECTION :INPUT)
     (SETQ *ALL-MY-DATA* (READ STREAM)))))

I'm going to get a syntax error.  So *PRINT-READABLY* tells Lisp
that programs doing printing should err at PRINT-time when they
fully well know that the result will not be re-readable.  Much better
to know your save failed and that you need to take alternate action
(while the image is still running on day 1) than to find out later.

This has happened to me more than once in the olden days.  I'm sure
to others as well.  The fix was:

 (DEFUN SAVE-ALL-MY-DATA-FOR-TOMORROW (FILE)
   (WITH-OPEN-FILE (STREAM FILE :DIRECTION :OUTPUT)
     (LET ((*PRINT-READABLY* T))
       (PRINT *ALL-MY-DATA* STREAM))))

[Actually, there are aalso "typical bugs" related to mismatch of
package, etc, too.  Hence really,


 (DEFUN SAVE-ALL-MY-DATA-FOR-TOMORROW (FILE)
   (WITH-OPEN-FILE (STREAM FILE :DIRECTION :OUTPUT)
     (WITH-STANDARD-IO-SYNTAX
       (PRINT *ALL-MY-DATA* STREAM))))

is better; it binds not only *PRINT-READABLY* but a number of
other things people often forget to bind that they should.

Now comes the problem of PRINC.

Here's a fact worth noting:

      No one calls PRINC ever in files to be
      re-readable so it's just nutty to change it's behavior.
      That is, if a program does:
        (PRINC *ALL-MY-DATA* STREAM)
      or even (PRINC *SOME-OF-MY-DATA* STREAM)
      we know that one of these things is true:
        (a) you're lost whether or not you're using *print-readably*
        (b) you're not re-reading with READ
        (c) you're implementing PRINT using PRINC as a sub-primitive.

Here's another observation:

 print-object methods often call PRINC out of tradition, often where
 write-string is desired.    Some of this is tradition.  Some is
 becuase ~A in format is used and there is no write-string operation
 in format.  Having *print-readably* randomly turn a ~A into ~S would
 be an unmitigated disaster becuase it would break print-object
 methods everywhere, making them insert quotes, backslashes, etc.
 all over the place.

As Erik points out, as far as the spec goes, there is no question
(PRINC "FOO") should print FOO, not "FOO" no matter the binding of
*PRINT-ESCAPE* or *PRINT-READABLY* that prevails outside the call to
PRINC, since PRINC binds both of these variables to false while it
executes, and so no code within it would be aware of the values
prevailing outside.

But I thought you might want to see the history/motivation so you
could feel comfortable that this is not an accident or typo.
From: Kent M Pitman
Subject: Re: princ & *print-readably*
Date: 
Message-ID: <sfwg1k7phti.fsf@world.std.com>
Sam Steingold <···@usa.net> writes:

>  Now I will be
> using with-standard-io-syntax.  But I have a question about it: CHKS says
> that it binds *print-circle* to nil.  Why?  Although it is the default
> value, this will prevent the reader from reading in the exact copy of
> the data that I wrote!

There's not much of a satisfying answer to this.  Some people think
*print-circle* being T is the only correct setting. Some do not work
with circular data structures and think the entire issue is not about
correctness but efficiency.

In fairness, if circular structure fails to print out correctly, it's
because it was circular and it probably doesn't terminate so probably 
you get something close to an error (at least you get a "problem of
some kind").

Then again, you might have set *PRINT-CIRCLE* globally to T knowing
you were working with circular objects, and it's pretty obnoxious for
a system macro to helpfully bind that back to NIL for no other purpose
than "normalizing the value".  I bet someone didn't anticipate that
particular problem.

It happened that sometimes when I made edits to the spec to simply add
a new thing, I forgot to use change markers, so you don't get a pointer from
issue DATA-IO in the hyperspec back to WITH-STANDARD-IO-SYNTAX even though
DATA-IO was the issue that introduced it.  But you can go to that issue
and read the text about it and not that it says that it was an "arbitrary"
choice and that you can bind it back manually if you care.

Probably the safest thing would be for this macro not to be binding
that particular variable at all...  But maybe someone else thought that
would also be inelegant.  I dunno.  Anyway, issue DATA-IO (which is in
CLHS) gives you the official read.