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

*print-readably* and printing numbers

11 views
Skip to first unread message

Raymond Toy

unread,
May 2, 2001, 6:05:51 PM5/2/01
to

On the cmucl mailing list, we are having a discussion on what
*print-readably* should when printing numbers.

Assume *read-default-float-format* is 'single-float and we do this:

(let ((*print-readably* t))
(print 1.0f0)
(print 1.0d0))

CMUCL produces

1.0
1.0d0

Clisp says

1.0f0
1.0d0

CMUCL produces different results if *read-default-float-format* is
'double-float:

1.0f0
1.0

I think Clisp is doing the right thing, although the others seem to be
compatible with CLHS.

Also, consider this (with *read-base* set to 10):

(write 42 :base 7 :readably t)

CMUCL and Lispworks Windows both print "60". Clisp prints "42."
(Note the point that is printed.)

CMUCL and Lispworks didn't print the answer readably in some sense.
Clisp did, but didn't honor the :base argument. I'm not sure which is
right, but I tend to agree with Clisp here.

I'm looking for some clarification here. I looked at the CLHS, and I
couldn't find anything that describes how *print-readably* interacts
with all of the things that could affect how things are read when
reading numbers.

Thanks,

Ray

Kent M Pitman

unread,
May 2, 2001, 11:47:02 PM5/2/01
to
Raymond Toy <t...@rtp.ericsson.se> writes:

I think *print-readably* was added toward the last minute and there wasn't
really a good understanding/consensus of what its impact is or should be.
That's why it's vague.

Looking at the definition of *print-readably*, I was surprised to see the
reference to the standard readtable, which somewhat implies that the present
readtable settings are ignored. The language is, I agree, vague on the issue
of what happens with regard to the printer control variables, but I assume
they are thought to be the same as they are now, as in the same general spirit
as described in 2.3.6 (Package Consistency Rules) and

IMO, you're under an implicit promise to make reader/printer things
match up, that is, to make sure that during any attempt to read back
in something you will have reader settings set to match how you
printed them out. I probably couldn't point you to any passage that
said this, though.

I personally don't think you're under a promise to gratuitously bind
the reader variables while you are doing the printing, though I can
see how someone might be paranoid about this. Again, I doubt I can
point to any passage of text to back up this feeling of mine, though.

I think that what *read-base* is set to when


(write 42 :base 7 :readably t)

is done does not matter; what matters is that when read is done, you
have managed to set base to 7; if you have not, you've violated the
read/print contract, IMO. Opinions could legitimately vary on this,
though.

I also think it's also reasonable to omit the "f0" in 1.0f0 if that's
the default floating print mode.

But those are just my personal prejudices, and anyone who claims
otherwise should be prepared with a specific passage to back them up.
My guess is that there isn't anything remarkably definitive. The
(non-binding) examples for *print-readably* give some hints as to
intent, but that's far from "specification".

Like I said, it's a latter-day feature and probably waiting on more
user experience to really be nailed down solid...

What would be more interesting (to me, at least) than knowing what
implementations do would be knowing whether anyone has run into any
problems where they used *print-readably* in any of these behaviors
expecting to be protected and ended up not protected. I would bet that
if people are following the proper print/read consistency guidelines,
they're adequately protected under any of the cited behaviors above.
But empirical data confirming or denying that would be good to have.

Raymond Toy

unread,
May 3, 2001, 10:42:13 AM5/3/01
to
>>>>> "Kent" == Kent M Pitman <pit...@world.std.com> writes:

Kent> What would be more interesting (to me, at least) than knowing what
Kent> implementations do would be knowing whether anyone has run into any
Kent> problems where they used *print-readably* in any of these behaviors
Kent> expecting to be protected and ended up not protected. I would bet that
Kent> if people are following the proper print/read consistency guidelines,
Kent> they're adequately protected under any of the cited behaviors above.
Kent> But empirical data confirming or denying that would be good to have.

The particular case I had in mind was f2cl which creates Lisp code
from Fortran. Assuming default values for all printer control vars,
f2cl will generate code like

(let ((x 42.0))
(declare (single-float x))
...)

If I should now compile and load this into Lisp but had
*read-default-float-format* set to 'double-float, then x is
initialized to a double-float, which contradicts the declaration.

I thought setting *print-readably* to T would cause f2cl to print 42.0
as 42f0 so that compiling the file would produce the right result.

But you are right---there are lots of implicit assumptions when
printing and reading. The only way to be sure is to agree on the
settings when printing and reading and make them consistent.

However, I find it conceptually nice if *print-readably* tried to
print things such that the impact of these implicit assumptions were
minimized.

Ray

Sam Steingold

unread,
May 3, 2001, 10:49:28 AM5/3/01
to
> * In message <sfw3dan...@world.std.com>
> * On the subject of "Re: *print-readably* and printing numbers"
> * Sent on Thu, 3 May 2001 03:47:02 GMT

> * Honorable Kent M Pitman <pit...@world.std.com> writes:
>
> I think *print-readably* was added toward the last minute and there
> wasn't really a good understanding/consensus of what its impact is or
> should be. That's why it's vague.

Aha!!! This clears things up!

One of the more confusing issues in the spec is pathname printing.
(see <http://clisp.sourceforge.net/impnotes.html#pathprint>)

Issue 276 PRINT-READABLY-BEHAVIOR:CLARIFY prescribes #p"" format which
is clearly ambiguous ( #p".bashrc" may be #.(make-pathname :type
"bashrc") or #.(make-pathname :name ".bashrc")).

OTOH, there is a clear and unambiguous #s(pathname) format in several
places in the CLHS:

HyperSpec/Body/fun_namestrin_h-namestring.html:

(setq q (make-pathname :host "kathy"
:directory
(pathname-directory *default-pathname-defaults*)
:name "getty"))
=> #S(PATHNAME :HOST "kathy" :DEVICE NIL :DIRECTORY directory-name
:NAME "getty" :TYPE NIL :VERSION NIL)


HyperSpec/Body/fun_parse-namestring.html

(setq q (parse-namestring "test"))
=> #S(PATHNAME :HOST NIL :DEVICE NIL :DIRECTORY NIL :NAME "test"
:TYPE NIL :VERSION NIL)
(parse-namestring "test")
=> #S(PATHNAME :HOST NIL :DEVICE NIL :DIRECTORY NIL :NAME "test"
:TYPE NIL :VERSION NIL), 4
(setq s (open xxx)) => #<Input File Stream...>
(parse-namestring s)
=> #S(PATHNAME :HOST NIL :DEVICE NIL :DIRECTORY NIL :NAME xxx
:TYPE NIL :VERSION NIL), 0
(parse-namestring "test" nil nil :start 2 :end 4 )
=> #S(PATHNAME ...), 15

HyperSpec/Body/fun_pathnamep.html
(setq q (pathname "test"))
=> #S(PATHNAME :HOST NIL :DEVICE NIL :DIRECTORY NIL :NAME "test" :TYPE NIL
:VERSION NIL)

I wonder why this #s(pathname...) syntax was not made the readable format?

--
Sam Steingold (http://www.podval.org/~sds)
You think Oedipus had a problem -- Adam was Eve's mother.

Kent M Pitman

unread,
May 3, 2001, 11:03:27 AM5/3/01
to
Raymond Toy <t...@rtp.ericsson.se> writes:

> The particular case I had in mind was f2cl which creates Lisp code
> from Fortran. Assuming default values for all printer control vars,
> f2cl will generate code like
>
> (let ((x 42.0))
> (declare (single-float x))
> ...)
>
> If I should now compile and load this into Lisp but had
> *read-default-float-format* set to 'double-float, then x is
> initialized to a double-float, which contradicts the declaration.

This is why I asked. You are violating the print/read rules if you don't
read the object with a compatible set of variable bindings to what you
printed it with.

In my personal opinion, it's not *print-readably*'s job to check that
you have that reader environment set up at print time. It's instead its
job merely to assure that it's printing things in a way that are consistent
with relevant printer control settings (which includes some, but not all
reader settings) such that re-reading is plausible.

*read-default-float-format* is a reader variable, but affects printing,
so I think you have to have it consistently bound. But *print-base* exists
for the precise purpose of saying "this is the base I will use on read".
Otherwise, we'd have just had a *print-and-read-base* which is used
both for the printer and reader. In that case, I personally don't think it's
*print-readably*'s job to say "you must bind an extra special variable here
even though it will not be used for anything during the printing". That just
takes time to bind and slows down multiprocessing (which has to bind/unbind
the special on every stack group switch) gratuitously.

> I thought setting *print-readably* to T would cause f2cl to print 42.0
> as 42f0 so that compiling the file would produce the right result.

In an implementation with only one floating format, for example, there'd
never be any reason to print the marker. *print-readably* is only about
re-reading in the same implementation, not across implementations. (maybe
that's a bug, but that's the definition.) And I think it's reasonable for
the printer to assume you'll bind the thing to the same value on read, so
even if you do have a distinct single and double format, if you have it
bound to double on printing and print a double, i think it's fair for the
system to expect you'll bind to double on read, so again it doesn't need
the marker.

> But you are right---there are lots of implicit assumptions when
> printing and reading. The only way to be sure is to agree on the
> settings when printing and reading and make them consistent.

Glad we agree on this.



> However, I find it conceptually nice if *print-readably* tried to
> print things such that the impact of these implicit assumptions were
> minimized.

It also has other things to worry about.

- efficiency - it's easy to slow down the printer A LOT if not careful

- correctness - when I say (write n :radix 7), you'd better have a darned
good reason not to write it in radix 7. i didn't just pick that number
casually.

The end result is a balance of many issues--not just a matter of the
simple application of "conservative principles" to an otherwise unconstrained
space.

Barry Margolin

unread,
May 3, 2001, 11:06:49 AM5/3/01
to
In article <4noftaw...@rtp.ericsson.se>,

Raymond Toy <t...@rtp.ericsson.se> wrote:
>But you are right---there are lots of implicit assumptions when
>printing and reading. The only way to be sure is to agree on the
>settings when printing and reading and make them consistent.

And this is the purpose of WITH-STANDARD-IO-SYNTAX. If you use this around
both the writing and reading code, you know that they'll be consistent.

--
Barry Margolin, bar...@genuity.net
Genuity, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.

Kent M Pitman

unread,
May 3, 2001, 11:08:22 AM5/3/01
to
Sam Steingold <s...@gnu.org> writes:

> I wonder why this #s(pathname...) syntax was not made the readable format?

I proposed it, but I think maybe too late. (We "feature froze" in
1988, if I recall, and finished in 1994, and published in 1995.)
There was a BIG gap in there where any number of good ideas were
canned for being "too late". A few features were added after 1988 if
there was really pressing need, but mostly it was only bug fixes.
Pity no one thought the inability to print readably in numerous
contexts was not a bug fix, but maybe that was my failure to make a
good case. In fairness, this would have required a lot of detail work
identifying names for things that didn't have names. [See the examples
for *print-readably* and the remarks about hash tables. Knowing whether
to call an array's storage :contents or :storage or whatever, etc. is an
issue.]

Kent M Pitman

unread,
May 3, 2001, 11:10:49 AM5/3/01
to
Kent M Pitman <pit...@world.std.com> writes:

> The end result is a balance of many issues--not just a matter of the
> simple application of "conservative principles" to an otherwise unconstrained
> space.

Maybe instead of just a boolean special controlling this, it should
instead be

(declare (readability 2) (efficiency 3) (correctness 1))

so that you could do cool math on it and surprise users with the
"necessary" outcome.

Raymond Toy

unread,
May 3, 2001, 2:10:49 PM5/3/01
to
>>>>> "Kent" == Kent M Pitman <pit...@world.std.com> writes:

Kent> In my personal opinion, it's not *print-readably*'s job to check that
Kent> you have that reader environment set up at print time. It's instead its
Kent> job merely to assure that it's printing things in a way that are consistent
Kent> with relevant printer control settings (which includes some, but not all
Kent> reader settings) such that re-reading is plausible.

At least by putting an exponent marker, re-reading is "more"
plausible.

Kent> In an implementation with only one floating format, for example, there'd
Kent> never be any reason to print the marker. *print-readably* is only about
Kent> re-reading in the same implementation, not across implementations. (maybe
Kent> that's a bug, but that's the definition.) And I think it's reasonable for
Kent> the printer to assume you'll bind the thing to the same value on read, so
Kent> even if you do have a distinct single and double format, if you have it
Kent> bound to double on printing and print a double, i think it's fair for the
Kent> system to expect you'll bind to double on read, so again it doesn't need
Kent> the marker.

If I somehow implied writing with one implementation and reading from
another, I was wrong. I am only looking at one implementation.

However, by your argument, I wouldn't have to bind *print-readably* to
anything to get floating-point numbers read back in correctly since
everything is supposed to be bound to the same thing at print and read
time.

Kent> - efficiency - it's easy to slow down the printer A LOT if not careful

True. I was only concerned with printing out floating-point numbers
and I think that efficiency is not an issue here. (FP printing is
already slow.) I have not considered the consequences for other
objects.

Kent> - correctness - when I say (write n :radix 7), you'd better have a darned
Kent> good reason not to write it in radix 7. i didn't just pick that number
Kent> casually.

Presumably, you also wanted *print-readably* bound to T in this case.
If not, then I don't see the issue there since it doesn't have to be
readable. Well, as someone pointed out in the CMUCL list, this could
be printed as #7r<nnn> in this case. Satisfies the spirit if not the
letter. :-)

Kent> The end result is a balance of many issues--not just a
Kent> matter of the simple application of "conservative
Kent> principles" to an otherwise unconstrained space.

Yes. *print-readably* is not clearly specified, and that's the way it
is. Wishing it were won't make it so. :-(

Ray

Barry Margolin

unread,
May 3, 2001, 3:25:20 PM5/3/01
to
In article <4nsnimu...@rtp.ericsson.se>,

Raymond Toy <t...@rtp.ericsson.se> wrote:
>However, by your argument, I wouldn't have to bind *print-readably* to
>anything to get floating-point numbers read back in correctly since
>everything is supposed to be bound to the same thing at print and read
>time.

IMHO, the main purpose of *PRINT-READABLY* is to catch you when you try to
print things that don't have any readable printed representation,
i.e. objects that print using #<...> notation. However, as an added
convenience, it also overrides variables like *PRINT-ESCAPE* and
*PRINT-GENSYM*, which control whether objects are printed in a readable
form, so you only have to set this one variable to get all their effects.

A number is readable in any base, so *PRINT-READABLY* isn't required to
force a specific base.

Kent M Pitman

unread,
May 3, 2001, 4:35:18 PM5/3/01
to
Barry Margolin <bar...@genuity.net> writes:

> IMHO, the main purpose of *PRINT-READABLY* is to catch you when you try to
> print things that don't have any readable printed representation,
> i.e. objects that print using #<...> notation.

Mine, too.

> However, as an added
> convenience, it also overrides variables like *PRINT-ESCAPE*

"One man's trash is another man's treasure."
Personally I hate that it overrides *PRINT-ESCAPE*.
I have tones of legacy programs that do (IF *PRINT-ESCAPE* ...)
and which are not sensitive to *PRINT-READABLY* and I often just
forget to put in the mention of *PRINT-READABLY* on new ones.
I think people should bind both. I think *PRINT-READABLY* should
describe the action of PRIN1, not force PRIN1 to occur.

> and
> *PRINT-GENSYM*, which control whether objects are printed in a readable
> form, so you only have to set this one variable to get all their effects.

But you hve to *test* several variables.



> A number is readable in any base, so *PRINT-READABLY* isn't required to
> force a specific base.

Right.

Moreover, since PRIN1 and PRINC on numbers do the same thing, one
would think that WRITE, which is neutral as to *PRINT-ESCAPE* when dealing
with numbers, would be the function to call when writing a number. Saves
fussing over a non-choice between PRIN1 and PRINC. Yet, if *PRINT-READABLY*
were to change what base things came out in, then WRITE would not be the
function to call in most number situations.

Raymond Toy

unread,
May 3, 2001, 5:13:57 PM5/3/01
to
>>>>> "Barry" == Barry Margolin <bar...@genuity.net> writes:

Barry> In article <4nsnimu...@rtp.ericsson.se>,


Barry> Raymond Toy <t...@rtp.ericsson.se> wrote:
>> However, by your argument, I wouldn't have to bind *print-readably* to
>> anything to get floating-point numbers read back in correctly since
>> everything is supposed to be bound to the same thing at print and read
>> time.

Barry> IMHO, the main purpose of *PRINT-READABLY* is to catch you when you try to
Barry> print things that don't have any readable printed representation,
Barry> i.e. objects that print using #<...> notation. However, as an added
Barry> convenience, it also overrides variables like *PRINT-ESCAPE* and
Barry> *PRINT-GENSYM*, which control whether objects are printed in a readable
Barry> form, so you only have to set this one variable to get all their effects.

If the assumption is that the print state and the read state are
intended to be consistent, then this seems to be the real (and only?)
purpose of *print-readably*. Since experts like you and Kent agree on
this point, who am I to disagree? :-)

Barry> A number is readable in any base, so *PRINT-READABLY* isn't required to
Barry> force a specific base.

But the number that is read has to be similar to the number that is
printed, so the bases do matter if they're different. But then the
print and read states aren't consistent, so perhaps this is
irrelevant.

Ray

Barry Margolin

unread,
May 3, 2001, 5:59:10 PM5/3/01
to
In article <4ng0emu...@rtp.ericsson.se>,

Right. Even without setting *PRINT-READABLY*, there's already the
requirement that reading a number will result in a number that's similar to
the number that was printed. In either case, this requirement is only in
effect if the number-related printer control variables are consistent.

I agree that this isn't clear in the standard. The ambiguity implies that
you must set these variables consistently, because the standard doesn't
guarantee that the right thing will happen otherwise.

Good rule of thumb when dealing with standards: assume the worst when
something is unclear. If something can possibly be interpreted in multiple
ways, there's a chance that different implementors will have chosen
different interpretations. If you can, avoid writing code that depends on
a particular interpretation. If you've seen my posts about when I think
LOOP is inappropriate, it's based on this principle (there's some known
ambiguity in the interaction between different LOOP keywords, so I
recommend avoiding complex combinations).

Perhaps things like this can be corrected in an update to the standard, but
then you still will have to deal with older implementations for a while. I
realize this sounds very cynical about the value of standards, but I don't
intend that. Most of the things you need to write commonly are pretty well
specified, but occasionally you run into corners that we weren't able to
specify as fully as necessary, either because we didn't notice the problem
or we simply ran out of time.

Mike McDonald

unread,
May 3, 2001, 6:54:03 PM5/3/01
to
In article <dueI6.9$Ip3.310@burlma1-snr2>,

Barry Margolin <bar...@genuity.net> writes:
> In article <4noftaw...@rtp.ericsson.se>,
> Raymond Toy <t...@rtp.ericsson.se> wrote:
>>But you are right---there are lots of implicit assumptions when
>>printing and reading. The only way to be sure is to agree on the
>>settings when printing and reading and make them consistent.
>
> And this is the purpose of WITH-STANDARD-IO-SYNTAX. If you use this around
> both the writing and reading code, you know that they'll be consistent.

And how does the producer of a Lisp file ensure that all potential consumers
of that file will wrap WITH-STANDARD-IO-SYNTAX around READ/EVAL/COMPILE/...?
(The LispMs at least had the :BASE option in the file's atribute line.) Most
Lisp code I've seen, and written, makes the false assumption that *READ-BASE*
is set to 10. Or should that be #10r10?

I guess the answer is that one cannot use any of the standard Lisp I/O
functions if the type when read back in is important. In Ray's case, he
probably needs to write his own print-int, print-float, print-double, ...
routines that'll produce output that's not sensitive to the setting of any of
the various *READ-???* variables.

Mike McDonald
mik...@mikemac.com

Kent M Pitman

unread,
May 3, 2001, 7:43:50 PM5/3/01
to
mik...@mikemac.com (Mike McDonald) writes:

> And how does the producer of a Lisp file ensure that all potential consumers
> of that file will wrap WITH-STANDARD-IO-SYNTAX around READ/EVAL/COMPILE/...?

The reading party's job.

> (The LispMs at least had the :BASE option in the file's atribute line.)

Aside about LispM's: The variables in Maclisp were called IBASE and BASE.
IBASE controled the input base, and BASE controlled the output base. There
was no OBASE, though many felt BASE should have been named OBASE. The Lispm
has this same naming in Zetalisp, if memory serves. Curiously, in file syntax
lines, Base: xxx; controls the ibase, not the base. As I recall, it
specifically does not bind BASE, in spite of its name. So in cases of
Base: 8; I believe some confusion can arise. I remember sending a bug report
about this eons ago when I first noticed it, but I think by time people did
as I was doing, it was too late to fix--too many things relying on current
behavior. So this is not a "new" problem...

> most


> Lisp code I've seen, and written, makes the false assumption that *READ-BASE*
> is set to 10. Or should that be #10r10?

I'm glad they do assume that. You have no idea how hard-fought this
little victory was. I waged a multi-year war many (though not all)
well-known lispers while at MIT who insisted that the default base of
8 in Maclisp and Zetalisp was the "right" base, that 8 was just purer
and better. We used to get regular bug reports that + was broken
because (+ 5 5) => 12, and the FAQ used to have to explain that + was
not broken, etc.

Today's problems are different than that, and I suppose that is the
quality of progress--not that things get fixed forever, but that we
move on eventually from one problem to whine about to another problem
to whine about.

Some day I hope to publish my notes on this conversation about why
base 8 was better. It was a fascinating discussion, and I hope with
the benefit of some time between then and now will come across as
appropriately humorous, even by those who stuck to 8.

> I guess the answer is that one cannot use any of the standard Lisp I/O
> functions if the type when read back in is important.

This ignores everything we have been saying.

The answer is that one can use any of the standard Lisp I/O functions if the
type when read back in is important, and the way you demonstrate that you
care enough to see this happen is you reproduce the appropriate environment.
If you don't do your part, why should the system do its part??

> In Ray's case, he
> probably needs to write his own print-int, print-float, print-double, ...
> routines that'll produce output that's not sensitive to the setting of any of
> the various *READ-???* variables.

NO. There are several *read-xxx* variables that are documented to
have an effect on both the printer and reader. See 22.1.1.1 (Multiple
Possible Textual Representations) where they are enumerated.
If you bind these properly, the normal I/O functions will do the right
thing.

cbbr...@hex.net

unread,
May 3, 2001, 7:59:46 PM5/3/01
to
Kent M Pitman <pit...@world.std.com> writes:
> I'm glad they do assume that. You have no idea how hard-fought this
> little victory was. I waged a multi-year war many (though not all)
> well-known lispers while at MIT who insisted that the default base
> of 8 in Maclisp and Zetalisp was the "right" base, that 8 was just
> purer and better. We used to get regular bug reports that + was
> broken because (+ 5 5) => 12, and the FAQ used to have to explain
> that + was not broken, etc.

Hmm... I'd think that base 12 would be preferable, as it's got
factors of 2 and 3, thus making it possible to represent more values
exactly.

Mind you, base 2x3x5x7, or 210, is less than 255, nicely fitting into
a byte, and is divisible by all those lovely primes... 210 seems a
nice base to play with...
--
(reverse (concatenate 'string "ac.notelrac.teneerf@" "454aa"))
http://vip.hex.net/~cbbrowne/resume.html
Now is a good time to spend a year dead for tax purposes.

Mike McDonald

unread,
May 4, 2001, 12:39:17 AM5/4/01
to
In article <sfw66fi...@world.std.com>,

Kent M Pitman <pit...@world.std.com> writes:
> mik...@mikemac.com (Mike McDonald) writes:
>
>> And how does the producer of a Lisp file ensure that all potential consumers
>> of that file will wrap WITH-STANDARD-IO-SYNTAX around READ/EVAL/COMPILE/...?
>
> The reading party's job.

And how is the reader suppose to know the "correct" settings? How does the
writer of a lisp file ensure that whoever calls LOAD or COMPILE-FILE has set
the variables correctly?

>> most
>> Lisp code I've seen, and written, makes the false assumption that *READ-BASE*
>> is set to 10. Or should that be #10r10?
>
> I'm glad they do assume that. You have no idea how hard-fought this
> little victory was.

Actually, I do. I've been around long enough to have to deal with the
default base being 8. At least in the ZetaLisp days there was a method to
ensure the read base was consistant with the base used when writing the file.
That's not the case today.

>> I guess the answer is that one cannot use any of the standard Lisp I/O
>> functions if the type when read back in is important.
>
> This ignores everything we have been saying.
>
> The answer is that one can use any of the standard Lisp I/O functions if the
> type when read back in is important, and the way you demonstrate that you
> care enough to see this happen is you reproduce the appropriate environment.

But as a writer, you don't have control over the read environment. That's
some other user's environment. Maybe he's a ZetaLisp fan and has *read-base*
set to 8. Maybe it's cbrown's environment and he has it set to 210 (decimal).

Mike McDonald
mik...@mikemac.com

Kent M Pitman

unread,
May 4, 2001, 2:49:58 AM5/4/01
to
mik...@mikemac.com (Mike McDonald) writes:

> In article <sfw66fi...@world.std.com>,
> Kent M Pitman <pit...@world.std.com> writes:
> > mik...@mikemac.com (Mike McDonald) writes:
> >
> >> And how does the producer of a Lisp file ensure that all potential consumers
> >> of that file will wrap WITH-STANDARD-IO-SYNTAX around READ/EVAL/COMPILE/...?
> >
> > The reading party's job.
>
> And how is the reader suppose to know the "correct" settings? How does the
> writer of a lisp file ensure that whoever calls LOAD or COMPILE-FILE has set
> the variables correctly?

I don't understand. Most input to LOAD or COMPILE is not generated by print.
But it's trivial if you are auto-generating a file to have boilerplate at
the front that does any necessary checks. e.g.,

(eval-when (:compile-toplevel :execute)
(unless (= *read-base* 10.) ...)
...)

> >> most
> >> Lisp code I've seen, and written, makes the false assumption that *READ-BASE*
> >> is set to 10. Or should that be #10r10?
> >
> > I'm glad they do assume that. You have no idea how hard-fought this
> > little victory was.
>
> Actually, I do. I've been around long enough to have to deal with the
> default base being 8. At least in the ZetaLisp days there was a method to
> ensure the read base was consistant with the base used when writing the file.
> That's not the case today.
>
> >> I guess the answer is that one cannot use any of the standard Lisp I/O
> >> functions if the type when read back in is important.
> >
> > This ignores everything we have been saying.
> >
> > The answer is that one can use any of the standard Lisp I/O functions if the
> > type when read back in is important, and the way you demonstrate that you
> > care enough to see this happen is you reproduce the appropriate environment.
>
> But as a writer, you don't have control over the read environment.

No, that's not true. You do have the ability to use notations that
are safe, assuming you have Lisp looking at your code at all. The
radixed things like 10. and #xAA are safe. You can use these to get a
foothold and make sure that things are safe, if you doubt it.

> That's some other user's environment. Maybe he's a ZetaLisp fan and
> has *read-base* set to 8. Maybe it's cbrown's environment and he has
> it set to 210 (decimal).

That you can't control the read environment is not something
lamentable, it is a fundamental property of the universe. Lamenting
things that are intrinisic to the universe is possible, I suppose, but
pointless. You'll never have 100% assurance someone won't try to read
your file as Teco. At some point, you'll just have to trust. So while
trusting the person will respect the fact that you've documented your file
to want to be interpreted by Lisp, why not trust them to do the rest
of the things you say you have to do.

Barry Margolin

unread,
May 4, 2001, 11:03:57 AM5/4/01
to
In article <VnqI6.111$7O2....@typhoon.aracnet.com>,

Mike McDonald <mik...@mikemac.com> wrote:
>In article <sfw66fi...@world.std.com>,
> Kent M Pitman <pit...@world.std.com> writes:
>> mik...@mikemac.com (Mike McDonald) writes:
>>
>>> And how does the producer of a Lisp file ensure that all potential consumers
>>> of that file will wrap WITH-STANDARD-IO-SYNTAX around READ/EVAL/COMPILE/...?
>>
>> The reading party's job.
>
> And how is the reader suppose to know the "correct" settings? How does the
>writer of a lisp file ensure that whoever calls LOAD or COMPILE-FILE has set
>the variables correctly?

Either don't mess with the global settings of the variables at all, or wrap
whatever you're doing in WITH-STANDARD-IO-SYNTAX, e.g.

(with-standard-io-syntax
(compile-file ...))

I think anyone who modifies the global settings of variables like
*READ-BASE* will soon learn the error of their way, since lots of things
will probably break. If you're writing a program that creates a file that
will be read by someone else, the best you can do is write it in the
standard I/O environment and expect them to read it in the same
environment.

If you want to go further, put something in your documentation saying that
this is necessary. But since this is necessary for just about everything,
it's generally considered the reader's problem, not yours.

Mike McDonald

unread,
May 4, 2001, 2:13:56 PM5/4/01
to
In article <sfwd79p...@world.std.com>,

Kent M Pitman <pit...@world.std.com> writes:
> mik...@mikemac.com (Mike McDonald) writes:
>
>> In article <sfw66fi...@world.std.com>,
>> Kent M Pitman <pit...@world.std.com> writes:
>> > mik...@mikemac.com (Mike McDonald) writes:
>> >
>> >> And how does the producer of a Lisp file ensure that all potential consumers
>> >> of that file will wrap WITH-STANDARD-IO-SYNTAX around READ/EVAL/COMPILE/...?
>> >
>> > The reading party's job.
>>
>> And how is the reader suppose to know the "correct" settings? How does the
>> writer of a lisp file ensure that whoever calls LOAD or COMPILE-FILE has set
>> the variables correctly?
>
> I don't understand. Most input to LOAD or COMPILE is not generated by print.

But that's precisely what Ray's question is about, f2cl! He's using lisp to
write lisp code, to be read back in in some environment that he doesn't
control.

>> But as a writer, you don't have control over the read environment.
>
> No, that's not true. You do have the ability to use notations that
> are safe, assuming you have Lisp looking at your code at all. The
> radixed things like 10. and #xAA are safe. You can use these to get a
> foothold and make sure that things are safe, if you doubt it.

And how do you force the standard print routines to include the appropriate
radix info? In my opinion, the answer should be by setting *print-readably* to
T. Otherwise there is no way using the standard print routines.

Mike McDonald
mik...@mikemac.com

Mike McDonald

unread,
May 4, 2001, 4:41:24 PM5/4/01
to
In article <EjCI6.136$7O2....@typhoon.aracnet.com>,
mik...@mikemac.com (Mike McDonald) writes:

I'm starting to rant again and mix several different issues together.
(integers vs floats, radix vs exponents) So let me try another approach.

The spec for *PRINT-READABLY* says:

----
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.

----

Let's start with printing floats first. The definition of similar numbers is:

3.2.4.2.2 - Two numbers S and C are similar if they are of the same type and
represent the same mathematical value.

I believe the important part is the phrase "they are of the same type"! To
me, that means that when a float is printed out with *PRINT-READABLY* set to
true, it has to be done in such a way that when read in by the same
implementation, it'll produce a float with the same type. I believe that the
value of *READ-DEFAULT-FLOAT-FORMAT* should be ignored because depending upon
its value to be the same at both print and read times would violate the
requirement that the read in number represent the same mathematical value and
type as the original value.

In the case of integers, relying on the value of "some other printer control
variable", aka *READ-BASE*, instead of including the radix information can
cause the read in number to have a completely different mathematical value. I
can't see how that meets the similarity requirement. My interpretation is that
if *PRINT-READABLY* is true, printing proceeds as if *PRINT-RADIX* was also
true.

Mike McDonald
mik...@mikemac.com

jo...@gnu.org

unread,
May 8, 2001, 9:50:11 PM5/8/01
to
> On the cmucl mailing list, we are having a discussion on what
> *print-readably* should when printing numbers.
> Assume *read-default-float-format* is 'single-float and we do this:
> (let ((*print-readably* t))
> (print 1.0f0)
> (print 1.0d0))
> CMUCL produces
> 1.0
> 1.0d0
> Clisp says
> 1.0f0
> 1.0d0
> CMUCL produces different results if *read-default-float-format* is
> 'double-float:
> 1.0f0
> 1.0
> I think Clisp is doing the right thing, although the others seem to be
> compatible with CLHS.

While we're on the topic of printing numbers, perhaps somebody can
offer some advice.

I was using Steele's PICTURE function (CLtL2, 12.5.3, p339; the HTML
version has two omitted lines (which have vital closing parens, so you
can find them easily), and adds spaces at the end which will mess up a
FORMAT string). I realize that it's not definitive, and has a few
minor bugs; for instance, if called without parameters, it tries to
coerce #'sqrt to a string.

What gets me is in the MOBY-GRID, when it tries to pick out the point
#c((/ pi 2) 0) for a tick mark. Under CMUCL, this causes the value
"1.5707963267948966d0" to be emitted, which is obviously not parsable
by PostScript (which doesn't support the "1d0" syntax).

I ended up coercing the values to single-floats in the printing
function, but that just doesn't seem to be the Right Way to handle the
issue. Besides the fact that it truncates the precision (which
admittedly isn't a problem for this particular application), it just
has a very icky feel to it.

I tried a format ~G, which was slightly better, but it still would
emit "-9.00000035762786900d-2" later.

Is there any way to tell CL to just display the number, but don't ever
use an exponential notation?

Sorry about the newbie question.

Thanks,
joelh

Pekka P. Pirinen

unread,
May 9, 2001, 8:34:12 AM5/9/01
to
> this causes the value "1.5707963267948966d0" to be emitted, which is
> obviously not parsable by PostScript (which doesn't support the
> "1d0" syntax). [...] I ended up coercing the values to

> single-floats in the printing function, but that just doesn't seem
> to be the Right Way to handle the issue.

No, it doesn't. Sounds like you have *READ-DEFAULT-FLOAT-FORMAT* set
to something other than DOUBLE-FLOAT. Setting that will fix the pi/2
case and any other numbers between 10^-3 (inclusive) and 10^7
(exclusive), which is probably enough for the PICTURE code.

> Is there any way to tell CL to just display the number, but don't
> ever use an exponential notation?

FORMAT ~F is for that purpose. (Even ~F is allowed to switch to
exponential if more than 100 digits would have to be printed, but
that's usually impractical, anyway.)
--
Pekka P. Pirinen, Harlequin Limited/Global Graphics
A race is a group of people united by a common misconception of
ancestry.

jo...@gnu.org

unread,
May 9, 2001, 5:58:41 PM5/9/01
to
>> this causes the value "1.5707963267948966d0" to be emitted, which is
>> obviously not parsable by PostScript (which doesn't support the
>> "1d0" syntax). [...] I ended up coercing the values to
>> single-floats in the printing function, but that just doesn't seem
>> to be the Right Way to handle the issue.
> No, it doesn't. Sounds like you have *READ-DEFAULT-FLOAT-FORMAT* set
> to something other than DOUBLE-FLOAT. Setting that will fix the pi/2
> case and any other numbers between 10^-3 (inclusive) and 10^7
> (exclusive), which is probably enough for the PICTURE code.

Yes, this is true, but this causes a lot of other floats to be printed
as "0.0f0", etc, which is the same problem with its reversable coat
turned around.

>> Is there any way to tell CL to just display the number, but don't
>> ever use an exponential notation?
> FORMAT ~F is for that purpose. (Even ~F is allowed to switch to
> exponential if more than 100 digits would have to be printed, but
> that's usually impractical, anyway.)

Perhaps I was unclear. I tried that (I may have omitted that in my
original post), but a normal ~F will print an exponentiation type
under CMUCL in this particular case:

* (format nil "~F" (/ pi 2))
"1.5707963267948966d0"

Specifying some parameters to ~F will address that:

* (format nil "~5F" (/ pi 2))
"1.571"

but at a loss of precision. While this loss is acceptable in this
application, it may not be in others. Granted, I could specify a
field length so wide that any float can fit:

* (format nil "~69F" (/ pi 2))
" 1.5707963267948966"

but that seems to be a bit ridiculous, not to mention depend on the
implementation.

Really, I'm just perplexed. CL's FORMAT facility is very powerful, so
it seems like there would be a way to just print a number, with no
exponentiation notation (probably with an "if possible within N
digits" clause) or padding.

Thanks,
joelh

PS: Just out of curiosity, does anybody know what implementation
Steele was using when he wrote that code?

Francis Leboutte

unread,
May 10, 2001, 4:51:40 AM5/10/01
to
jo...@gnu.org wrote:

>...


>Perhaps I was unclear. I tried that (I may have omitted that in my
>original post), but a normal ~F will print an exponentiation type
>under CMUCL in this particular case:
>
>* (format nil "~F" (/ pi 2))
>"1.5707963267948966d0"
>
>Specifying some parameters to ~F will address that:
>
>* (format nil "~5F" (/ pi 2))
>"1.571"
>
>but at a loss of precision. While this loss is acceptable in this
>application, it may not be in others. Granted, I could specify a
>field length so wide that any float can fit:
>
>* (format nil "~69F" (/ pi 2))
>" 1.5707963267948966"
>
>but that seems to be a bit ridiculous, not to mention depend on the
>implementation.
>
>Really, I'm just perplexed. CL's FORMAT facility is very powerful, so
>it seems like there would be a way to just print a number, with no
>exponentiation notation (probably with an "if possible within N
>digits" clause) or padding.
>

Same thing with ACL5

(format nil "~F" 1.5707963267948966d0)
;;;> "1.5707963267948966d0"

(format nil "~,20F" 1.5707963267948966d0)
;;;> "1.57079632679489660000"

This seems contradictory to the following (from the 22.3.3.1 ANSI CL entry,
Tilde F: Fixed-Format Floating-Point):
If both w and d are omitted, then the effect is to print the value using
ordinary free-format output; prin1 uses this format for any number whose
magnitude is either zero or between 10-3 (inclusive) and 107 (exclusive).

BTW

(format nil "~F" 1.5707963267948966)
;;;> "1.5707964"
--
www.algo.be
Logo programming : www.algo.be/logo.html

0 new messages