Re: Pretty printing experts, pretty please?



Mark Wooding <mdw@xxxxxxxxxxxxxxxx> writes:

Michael Weber <mw+google@xxxxxxxxx> wrote:
[...]
Note that t designates *terminal-io*, not *standard-output*.

Really?

Heh. T _is_ a stream designator for terminal I/O, but FORMAT does not
take a stream designator as its first argument. :) Mostly all of the
other I/O functions do take stream designators. (Which means they do
not accept NIL as an argument to do what a lot of people sometimes
request but would be messy to implement.)

CLHS 22.3:

: format sends the output to destination. [...] If destination is t,
: the output is sent to standard output.

Right.

For (almost?) all other output functions, specifying the destination as
NIL means *STANDARD-OUTPUT* and T means *TERMINAL-IO*; but since NIL as
a format destination means `return me a string', I guess they thought
the inconsistency was worth it.

I think that was the argument, yes.

Random walk through historical recollections follows.

Understand that in MACLISP, the NIL = standard output and T = terminal
I/O convention arose on systems [PDP-10] where you might really want
to use the real terminal (there was no window system). There was a
long and complicated transition in MACLISP from Old I/O (which was not
stream-based) to New I/O (which was, but which didn't have
programmable streams, only the terminal and files and very much later
Software File Arrays (SFA's) which were finally more like streams. But
the _real_ traditional function of the NIL/T distinction was to grandfather
in the Old I/O mechanism (which defaulted the stream and hence fit better
in the model of thinking of using standard input and standard output) and
the New I/O mechanism, with NIL (or omitted) selecting the old way and
T selecting the new way. But T was really just shorthand for either TYI
on input or TYO on output. (The problem was that Maclisp had no thing
which was both TYI and TYO, so T was able to pun between them... or you
could use (status ttycons tyi) to get tyo or (status ttycons tyo) to get
to tyi... In general, an input stream was trying to have a ttycons'd other
as a way of secretly allowing bidirectional streams. [Note: TYI and TYO also
were the names of READ-CHAR and WRITE-CHAR in MACLISP, when taken as function
names rather than variable names... so don't get confused there.]

Then on the LispM they tried to allow all of this even though they'd never
had Old I/O and they instead added standard-input and standard-output (later
*standard-input* and *standard-output* when CL arrived). Normally on the
LispM, *standard-input* and *standard-output* were set up to be synonym
streams for *terminal-io*, and because the LispM had windowing, every window
came with *terminal-io* bound to the window itself and *standard-input* and
*standard-output* bound to synonym streams for the window, which you could
rebind to other things as needed (but you were meant to leave *terminal-io*
alone). But this made *terminal-io* a rational thing to output to at least
a bit more often than it now is (since some implementations like LispWorks
bind *terminal-io* to what the Lisp Machine would have called the "cold
load stream"--a pre-window system bootstrap stream on the LispM but in
LispWorks a stream to the DOS or CommandPrompt window that is creating the
Lisp and that ordinarily the user would never see... so outputing to it is
mysterious... at least on the LispM if something did I/O to the cold load,
the system would figure that no one was seeing it and would arrange to bug
you about looking at it in a pop-up window instead of having it fall silent).

But FORMAT was not a Maclisp function originally. It was probably added
backported to Maclisp later in the day with reduced functionality but mostly
people just used lots of princ's, prin1's, tyo's, and terpri's. (Trivia:
terpri returns NIL in MACLISP and PRINT/PRIN1/TYO all returned T. So if you
were putting debugging info in conditionals, you'd want to do
(AND (NOT (TERPRI)) (PRIN1 X) (TYO 32.) X)
for example... I used to love those (NOT (TERPRI)) things since it made it
look like you weren't going to TERPRI... Btw, in case anyone is curious,
the reason Maclisp did not return the argument was that it would require
heap-consing integers in number-declared code, and they wanted not to create
a lot of unnecessary garbage... not that the GC was all that slow in a
no-virtual-memory system, but it was still extra space, even temporarily,
given MACLISP had a fixed upper limit on storage on the PDP-10 of 256K words
(about 1.25 megabytes, since those were 36 bit words). Ah, the good old days,
when life was so much simpler. Amazing we got any work done at all, given
that the chief programming tool was the shoehorn.

To be honest, I actually think T as the argument for FORMAT _might_
have been a misunderstanding--I'm not sure, though. I think a lot of
people thought PRIN1 of something to T actually did mean print to
standard output... I'm not sure which came first--whether people
thought that because FORMAT did it or FORMAT did it because it didn't
understand the convention. But you're right that the NIL case was
pretty much "don't do output" and kind of had to be NIL, so it was not
open to negotiation. And, really, no one does output directly to
*TERMINAL-IO*; the function of *TERMINAL-IO* (at least on the LispM)
was more of a bootstrapping issue for a window to decide if you wanted
to do raw output to the window or to do I/O calls efficiently).

(I think I'd rather have seen a destination of :STRING or something to
indicate that a string was wanted, but I suspect FORMAT predates
keywords.)

Keywords were there in 1981 as illustrated here:
http://www.unlambda.com/lmman/lmman_1.html
Search for "(:)". My older LispM manuals are not at the location
I'm posting from so I couldn't search hardcopy to see if they were
there in, say, 1979 when the black lispm was out, but I think that
version used names like tv-beep rather than tv:beep later, so you
might be right that format predates that.

:string would have looked ugly though. Frankly, I never understood
why they didn't just have (format-string ...) which would have been
fewer chars that (format :string ...). But the REAL reason to do it
as a separate function is the dataflow in/out. You've got to implement
it totally differently inside for the string case and the non-string case,
and the caller has to be equally aware of the difference because one
is for-value and one is for-side-effect.

.



Relevant Pages

  • Re: Problem reading a binary file in fortran
    ... To call it 'stream' isn't much of an improvement. ... the I/O support library imposing any record structure (or any other ... any explicit specification should be orthogonal to whether format ...
    (comp.lang.fortran)
  • Re: Problem reading a binary file in fortran
    ... one of those spellings. ... Stream is what C calls files. ... the I/O support library imposing any record structure (or any other ... any explicit specification should be orthogonal to whether format ...
    (comp.lang.fortran)
  • Re: Problem reading a binary file in fortran
    ... Records and buffers are "programmer stuff," not mathematics. ... I disagree that record I/O was or is a hardware concession. ... That's what F2003 'stream' ... under format control. ...
    (comp.lang.fortran)
  • Re: Data table text I/O package?
    ... regular and homogenuous data in mind. ... Given a data format much like in, ... I said XML is good for parsing of data if you cannot tell in advance that the data stream is totally free of errors. ... However, if some data item contains a separator due to an error, you loose the whole stream, or use the wrong data without noticing this, in the worst case. ...
    (comp.lang.ada)
  • Re: Variable length/precision formats?
    ... having it work like VFEs ... indirect interactions with the I/O list, ... The feature is ... the *FORMAT* is still list-directed in the above. ...
    (comp.lang.fortran)