Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

The history of print, prin1, and princ?

118 views
Skip to first unread message

Erik Naggum

unread,
Dec 9, 2001, 1:33:02 AM12/9/01
to
When teaching Common Lisp to a friend, a whole lot of interesting
questions have come up, about half of which I have been able to answer
right away, and the rest requiring quite a bit of research -- probably
the best reward a teacher can get. However, I am stumped for answers to
both the name and functionality of the print family of functions.

Why does print terminate with a space? (Starting with a newline is an
obvious feature, and is not questioend. :) What functionality need does
or did this fill? Do people avoid print because of this? (In Lisp 1.5,
print prints one S-expression on a line or punch card.)

How did the name "prin1" arise? In Lisp 1.5, prin1 prints an atomic
symbol, only, not an S-expression. In Common Lisp, it not only takes an
S-expression, but exists in a prin1-to-string version, as well, while
print does not have a print-to-string version.

And where did the name "princ" come from? It is not equally ancient as
the other functions, but also has a corresponding princ-to-string version.

For now, I have recommended write, write-to-string, and format instead of
the print family, but as names, print-object and print-unreadable-object
still hang around despite not producing delimiters associated with print.

///
--
The past is not more important than the future, despite what your culture
has taught you. Your future observations, conclusions, and beliefs are
more important to you than those in your past ever will be. The world is
changing so fast the balance between the past and the future has shifted.

Kent M Pitman

unread,
Dec 9, 2001, 6:08:17 AM12/9/01
to
Erik Naggum <er...@naggum.net> writes:

> When teaching Common Lisp to a friend, a whole lot of interesting
> questions have come up, about half of which I have been able to answer
> right away, and the rest requiring quite a bit of research -- probably
> the best reward a teacher can get. However, I am stumped for answers to
> both the name and functionality of the print family of functions.
>
> Why does print terminate with a space? (Starting with a newline is an
> obvious feature, and is not questioend. :) What functionality need does
> or did this fill? Do people avoid print because of this? (In Lisp 1.5,
> print prints one S-expression on a line or punch card.)

In older dialects, if I remember right, Newline was not an atom
breaker. If you had a very long number of symbol, it would get a CRLF
at the end of line and would get repatriated later. The Space assured
a token break. In CL, this is not an issue, but I think the behavior was
probably retained for cultural (and maybe data file) compatibility.

Some old programs also did stuff like:
(progn (print 'input?) (read))
and expected there to be a space...

> How did the name "prin1" arise? In Lisp 1.5, prin1 prints an atomic
> symbol, only, not an S-expression.

I asked this question of ATAN2 once expecting to hear that ATAN2 was the
two argument version of ATAN. But I was told it was preceded by ATAN1 and
ATAN1A, or some such, which were just assembly language entry points, and
that it was a pure accident that ATAN2 had the name it had. I rather
suspect the same is true of PRIN1 and PRINC, though have no special reason
to believe it so--just that suspicion. I'll see if I can get JonL White
to comment.

> In Common Lisp, it not only takes an
> S-expression, but exists in a prin1-to-string version, as well, while
> print does not have a print-to-string version.

I think there was a desire to focus on PRIN1 (or even WRITE) rather
than PRINT, retaining print for historical purposes. But I think it was
badly managed.



> And where did the name "princ" come from? It is not equally ancient as
> the other functions, but also has a corresponding princ-to-string version.

In Maclisp, there were also functions EXPLODE, EXPLODEN, and EXPLODEC which
may help you to understand this. I believe the "C" to be for Character.
If I recall, EXPLODE returns a list of chars that PRIN1 would print, with
chars represented as symbols. EXPLODEN returns what PRINC would print,
with chars represented as integers, and EXPLODEC returns what PRINC would
print with characters represented as symbols. That is:
(EXPLODE '(|A B|)) => (/( /| A | | B /| /))
(EXPLODEN '(|A B|)) => (40 65 32 66 41)
(EXPLODEC '(|A B|)) => (/( A | | B /()
remembering that / not \ was the syntax escape for Maclisp.
There were also functions FLATSIZE (to tell the width of what prin1 would
print) and FLATC (to tell the wdith that PRINC would print). But it's the
N (numeric) and C (character) thing on EXPLODEN/EXPLODEC that leads me to
believe this is what the C/N suffixes mean.

Again, though, I'll ask JonL.

> For now, I have recommended write, write-to-string, and format instead of
> the print family, but as names, print-object and print-unreadable-object
> still hang around despite not producing delimiters associated with print.

I don't see a serious problem with that approach, but...

I think it's unfortunate that PRINT-OBJECT isn't called WRITE-OBJECT.
It's not called just when PRINT is called. PRINT-UNREADABLE-OBJECT has
the same problem, though should perhaps be WRITE-UNREADABLE-OBJECT.
Oh well.

The problem I have with WRITE is that in most implementations, keyargs are
slow to decode. Not a language problem, per se, but still worrisome. Also,
in practice, I've found people to be not good about selecting the right
one of :escape t and :escape nil. Often they just take the default, thinking
on the basis of too little testing, that it will just get the right value.
PRIN1 vs PRINC forces people to think harder.

Thomas F. Burdick

unread,
Dec 9, 2001, 5:48:19 PM12/9/01
to
Kent M Pitman <pit...@world.std.com> writes:

> The problem I have with WRITE is that in most implementations, keyargs are
> slow to decode. Not a language problem, per se, but still worrisome.

But won't that probably be down in the noise of I/O? I could
understand that concern for WRITE-TO-STRING, but for plain old WRITE,
it seems like it'd be a tiny hit compared to doing I/O.

It's too bad that most implementations don't do a good job with
keyword args, though. For things like local functions, and functions
in the CL package, it's pretty easy to just have an argument-parsing
entry point and a non-parsing one. Of course, I've just started
debugging that part of my compiler, so maybe there's something I'm
missing here ... but it doesn't seem too hard, yet.

--
/|_ .-----------------------.
,' .\ / | No to Imperialist war |
,--' _,' | Wage class war! |
/ / `-----------------------'
( -. |
| ) |
(`-. '--.)
`. )----'

Erik Naggum

unread,
Dec 9, 2001, 6:25:58 PM12/9/01
to
* Kent M Pitman

| The problem I have with WRITE is that in most implementations, keyargs are
| slow to decode. Not a language problem, per se, but still worrisome.

If this is the case, does it apply to the number of keyword arguments in
the lambda list or in the actual call? Is it that write is expected to
bind the corresponding special variables in the keyword decoding that
makes write slower?

| Also, in practice, I've found people to be not good about selecting the
| right one of :escape t and :escape nil. Often they just take the
| default, thinking on the basis of too little testing, that it will just
| get the right value. PRIN1 vs PRINC forces people to think harder.

Well, in my experience, failure to understand the interaction of the
printer control variables is pervasive. It appears to be very hard for
some people to get into the habit of thinking about them, and they write
amazingly buggy code.

Thank you for the elaborate answer.

Kent M Pitman

unread,
Dec 10, 2001, 3:20:57 AM12/10/01
to
Erik Naggum <er...@naggum.net> writes:

> * Kent M Pitman
> | The problem I have with WRITE is that in most implementations, keyargs are
> | slow to decode. Not a language problem, per se, but still worrisome.
>
> If this is the case, does it apply to the number of keyword arguments in
> the lambda list or in the actual call? Is it that write is expected to
> bind the corresponding special variables in the keyword decoding that
> makes write slower?

Several people caught on this. This is just an impression I have.
Not very scientific.

I would expect implementations to rewrite keycalls as positional
calls. I think it can be done in general, but some implementations do
it only for common patterns or not at all.

I think it's the number of actual args that matters, but not entirely.
Surely no keyargs given is fast. :) Obviously, more things in the
lambda list means more things to check against if you want to see if a
keyarg given is actually valid, if it wasn't tested at compile time...

Kent M Pitman

unread,
Dec 11, 2001, 8:34:22 AM12/11/01
to
Kent M Pitman <pit...@world.std.com> writes:

> > How did the name "prin1" arise? In Lisp 1.5, prin1 prints an atomic
> > symbol, only, not an S-expression.
>
> I asked this question of ATAN2 once expecting to hear that ATAN2 was the
> two argument version of ATAN. But I was told it was preceded by ATAN1 and
> ATAN1A, or some such, which were just assembly language entry points, and
> that it was a pure accident that ATAN2 had the name it had. I rather
> suspect the same is true of PRIN1 and PRINC, though have no special reason
> to believe it so--just that suspicion. I'll see if I can get JonL White
> to comment.

JonL passed along this reply:

Over the years, I've modified my "recall" of the print issues. But it
seemed clear to me that the princ/prin1/print series were a staged effort at
writing the text-representation-printer in Lisp. (1) "PRINt the Characters"
of some object, (2) PRINt the characters of 1 particular object in suuch a
way that the "identity" of the object can be preserved if possible, (3)
PRINT compound object allowing for the need to return the "carriage" of type
keys and advance the line/paper-feed on thes old Model 33 and 35 TTY units.

0 new messages