From: Rolf Wester
Subject: Lisp read and writ
Date: 
Message-ID: <3BD57D8A.F6FD710C@ilt.fhg.de>
Hi,

One can use CL read and write functions to store and retrieve Lisp
objects from a file:

(setq m (make-array 10 :initial-element 1.0))
(with-open-file (out "array.dat" :dirction :output)
    (write m :stream out))
(with-open-file (in "array.dat" :dirction :input)
    (setq m2 (read in)))

Is it possible to do something like that with class instances?

(defclass myclass ()
    ((x :accessor :x :initform 1.0)))
(setq myobj (make-instance 'myclass))
(with-open-file (out "obj.dat" :dirction :output)
    (write myobj :stream out))
(with-open-file (in "obj.dat" :dirction :input)
    (setq myobj2 (read in)))

I tried this with CMUCL, CLISP and ACL60 but got error messages. Is
there any way
to let write and read do the job instead of doing it by hand?

With kind regards

Rolf

From: Sam Steingold
Subject: Re: Lisp read and writ
Date: 
Message-ID: <upu7e5k4o.fsf@xchange.com>
> * In message <·················@ilt.fhg.de>
> * On the subject of "Lisp read and writ"
> * Sent on Tue, 23 Oct 2001 16:24:15 +0200
> * Honorable Rolf Wester <······@ilt.fhg.de> writes:
>
> One can use CL read and write functions to store and retrieve Lisp
> objects from a file:
> 
> (setq m (make-array 10 :initial-element 1.0))
> (with-open-file (out "array.dat" :dirction :output)
>     (write m :stream out))

you really should wrap such things in WITH-STANDARD-IO
please see WRITE-TO-FILE in CLOCC/CLLIB/fileio.lisp

> (with-open-file (in "array.dat" :dirction :input)
>     (setq m2 (read in)))
> 
> Is it possible to do something like that with class instances?
> 
> (defclass myclass ()
>     ((x :accessor :x :initform 1.0)))
> (setq myobj (make-instance 'myclass))
> (with-open-file (out "obj.dat" :dirction :output)
>     (write myobj :stream out))
> (with-open-file (in "obj.dat" :dirction :input)
>     (setq myobj2 (read in)))
> 
> I tried this with CMUCL, CLISP and ACL60 but got error messages. Is
> there any way to let write and read do the job instead of doing it by
> hand?

please see CLOCC/CLLIB/closio.lisp
it defines an i/o syntax for CLOS objects.

please note that this is _not_ fool-proof: if you have some fancy
INITIALISE-INSTANCE methods, you will lose with this approach.
otherwise you are fairly safe.

-- 
Sam Steingold (http://www.podval.org/~sds)
Keep Jerusalem united! <http://www.onejerusalem.org/Petition.asp>
Read, think and remember! <http://www.iris.org.il> <http://www.memri.org/>
Illiterate?  Write today, for free help!
From: Barry Margolin
Subject: Re: Lisp read and writ
Date: 
Message-ID: <y7fB7.4$mE.97@burlma1-snr2>
In article <·················@ilt.fhg.de>,
Rolf Wester  <······@ilt.fhg.de> wrote:
>One can use CL read and write functions to store and retrieve Lisp
>objects from a file:
...
>Is it possible to do something like that with class instances?

By default, CLOS instances don't have a readable printed representation,
because the mechanisms for reconstructing the objects are class-dependent.
If you want to be able to write your objects readably, you must define a
PRINT-OBJECT method for the class and a readable printed representation
(typically this means defining a reader macro).

-- 
Barry Margolin, ······@genuity.net
Genuity, Woburn, 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.
From: Kent M Pitman
Subject: Re: Lisp read and writ
Date: 
Message-ID: <sfwitd6za18.fsf@world.std.com>
Barry Margolin <······@genuity.net> writes:

> In article <·················@ilt.fhg.de>,
> Rolf Wester  <······@ilt.fhg.de> wrote:
> >One can use CL read and write functions to store and retrieve Lisp
> >objects from a file:
> ...
> >Is it possible to do something like that with class instances?
> 
> By default, CLOS instances don't have a readable printed representation,
> because the mechanisms for reconstructing the objects are class-dependent.
> If you want to be able to write your objects readably, you must define a
> PRINT-OBJECT method for the class and a readable printed representation
> (typically this means defining a reader macro).

What Barry says is right, but also you can write a MAKE-LOAD-FORM method
in order to be able to externalize instances to a binary file.  I don't
know whether there's a constraint that READ/PRINT be used to a character
file; if there is, I guess you're stuck with the solution Barry says.  But
personally I'd always wwant to at least consider binary...  We've discussed
this several times before on this group, so searching for MAKE-LOAD-FORM
in www.deja.com's newsgroup archives would probably get you some help.  Btw, 
I think there's a worked implementatio of packaging up this facility into
someting like the Lispm's SYS:DUMP-FORMS-TO-FILE at the CMU AI repository
or the ALU web site.  Again, I'd use the newsgroup archives to find out.
Search probably for "dump" and "make-load-form"?
From: Kent M Pitman
Subject: Re: Lisp read and writ
Date: 
Message-ID: <sfwk7xmza94.fsf@world.std.com>
Rolf Wester <······@ilt.fhg.de> writes:

> One can use CL read and write functions to store and retrieve Lisp
> objects from a file:
> 
> (setq m (make-array 10 :initial-element 1.0))
> (with-open-file (out "array.dat" :dirction :output)
>     (write m :stream out))

You must give the :ESCAPE T :READABLY T arguments to WRITE here if you
don't wish to gamble losing your data randomly.

By default, WRITE will pick up the defaults for these from *PRINT-ESCAPE*
and *PRINT-READABLY*, which can be set to any arbitrary value at the
time your function is called.  If both are set to NIL, your data will
be written to the file in non-rereadable form.
From: Daniel Lakeland
Subject: Re: Lisp read and writ
Date: 
Message-ID: <20011023.093822.1139901474.1276@silnospamcon.com>
In article <···············@world.std.com>, "Kent M Pitman"
<······@world.std.com> wrote:

> Rolf Wester <······@ilt.fhg.de> writes:
> 
>> One can use CL read and write functions to store and retrieve Lisp
>> objects from a file:
>> 
>> (setq m (make-array 10 :initial-element 1.0)) (with-open-file (out
>> "array.dat" :dirction :output)
>>     (write m :stream out))
> 
> You must give the :ESCAPE T :READABLY T arguments to WRITE here if you
> don't wish to gamble losing your data randomly.
> 
> By default, WRITE will pick up the defaults for these from
> *PRINT-ESCAPE* and *PRINT-READABLY*, which can be set to any arbitrary
> value at the time your function is called.  If both are set to NIL, your
> data will be written to the file in non-rereadable form.

can't you just use prin1 here as well? 

My impression is that prin1 forces a re-readable representation without
having to bind any values or pass extra parameters.
From: Barry Margolin
Subject: Re: Lisp read and writ
Date: 
Message-ID: <zihB7.18$mE.598@burlma1-snr2>
In article <·······························@silnospamcon.com>,
Daniel Lakeland <········@silnospamcon.com> wrote:
>can't you just use prin1 here as well? 
>
>My impression is that prin1 forces a re-readable representation without
>having to bind any values or pass extra parameters.

No.  PRIN1 forces *PRINT-ESCAPE* to be true, but doesn't have anything to
do with *PRINT-READABLY*.

-- 
Barry Margolin, ······@genuity.net
Genuity, Woburn, 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.
From: Daniel Lakeland
Subject: Re: Lisp read and writ
Date: 
Message-ID: <20011023.150640.1359512183.2196@silnospamcon.com>
In article <···············@burlma1-snr2>, "Barry Margolin"
<······@genuity.net> wrote:

> In article <·······························@silnospamcon.com>, Daniel
> Lakeland <········@silnospamcon.com> wrote:
>>can't you just use prin1 here as well?
>>
>>My impression is that prin1 forces a re-readable representation without
>>having to bind any values or pass extra parameters.
> 
> No.  PRIN1 forces *PRINT-ESCAPE* to be true, but doesn't have anything
> to do with *PRINT-READABLY*.


Interesting: According to the CLHS

"prin1 produces output suitable for input to read. It binds *print-escape* to
true."

So my reading of this is that it acts as though *print-readably* were
true, perhaps even if it isn't. it does mention that prin1 and print
don't bind *print-readably* so I'm confused.

Should I bind *print-readably* before using prin1 to output a readable
representation?
From: Tim Bradshaw
Subject: Re: Lisp read and writ
Date: 
Message-ID: <ey3itd5ctmv.fsf@cley.com>
* Daniel Lakeland wrote:
> "prin1 produces output suitable for input to read. It binds *print-escape* to
> true."

> So my reading of this is that it acts as though *print-readably* were
> true, perhaps even if it isn't. it does mention that prin1 and print
> don't bind *print-readably* so I'm confused.

*PRINT-ESCAPE* and *PRINT-READABLY* have different meanings:

*PRINT-ESCAPE* means, loosely, `print readably if you can, but print anyway';

*PRINT-READABLY* means, loosely, `print readably: if you can't do so,
signal an error'.

> Should I bind *print-readably* before using prin1 to output a readable
> representation?

Yes, if you want to be sure that you can read it.

Note that a common bug in PRINT-OBJECT methods is not to listen to
*PRINT-READABLY*: it's not optional to signal an error if you can't
print something readably when it is true.

--tim
From: Barry Margolin
Subject: Re: Lisp read and writ
Date: 
Message-ID: <yfBB7.34$mE.2463@burlma1-snr2>
In article <·······························@silnospamcon.com>,
Daniel Lakeland <········@silnospamcon.com> wrote:
>Should I bind *print-readably* before using prin1 to output a readable
>representation?

It doesn't do that.  The only difference is whether an error is signalled
while printing or reading.  If you bind *print-readably*, an error will be
signalled when you try to print an object that doesn't have a readable
printed representation (e.g. a hash table).  Otherwise, it will print with
#<...> syntax, which will cause an error when you try to read it.

-- 
Barry Margolin, ······@genuity.net
Genuity, Woburn, 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.
From: Kent M Pitman
Subject: Re: Lisp read and writ
Date: 
Message-ID: <sfw7ktlvww0.fsf@world.std.com>
Barry Margolin <······@genuity.net> writes:

> 
> In article <·······························@silnospamcon.com>,
> Daniel Lakeland <········@silnospamcon.com> wrote:
> >Should I bind *print-readably* before using prin1 to output a readable
> >representation?
> 
> It doesn't do that.  The only difference is whether an error is signalled
> while printing or reading.  If you bind *print-readably*, an error will be
> signalled when you try to print an object that doesn't have a readable
> printed representation (e.g. a hash table).  Otherwise, it will print with
> #<...> syntax, which will cause an error when you try to read it.

The confusing part for people is that *PRINT-ESCAPE* selects the "notation"
but *PRINT-ESCAPE* enforces "readability".  People might think CL notation
IS readable, but it is not necessarily.

For example, #<...> is a defined part of the notation, and its definition
is to be "not readable".  PRINT-UNREADABLE-OBJECT outputs this notation, but
only if *PRINT-READABLY* is false; if it is true, as Barry points out,
it will signal an error.  But it's important to understand that it is long
Lisp tradition to have lots of things that are not re-readable.

Even some things that are in Lispy notation don't really "properly re-read".
For example, a displaced array or an array with adjustability will lose 
that kind of info when merely printed in Lispy notation.  An adjustable 
string "foo" and a non-adjustable string "foo" look the same.  Some printers
will go to more trouble when *PRINT-READABLY* is turned on to show these
in ways that do not lose information, but at the expense that a lot of
visual niceness is lost.

As someone else noted, even just (PRIN1 5) is going to have trouble if
*PRINT-BASE* is set to 4 but *PRINT-RADIX* is NIL and *READ-BASE* is 10.
(decimal).    As someone pointed out, it helps to make sure you have a 
read/print consistent environment using WITH-STANDARD-IO-SYNTAX, but 
if you aren't going to do that, at least again *PRINT-READABLY* will help
some to avoid these problems.

Remember that MOST uses of PRIN1 are for the interactive read-eval-print loop
and will not ACTUALLY be re-read, so having this ability to have a visual
representation that is "mostly re-readable" but that tolerates other things
like stream objects, perhaps as
 #<SYSTEM:FILE-STREAM "/joe/foo.lisp" 45% 2ae57>
is still quite handy.  I use this a *lot* and PRINT would be completely broken
to me if I had to see that in re-readable form.

The concern about re-readability came when some people had used ordinary
PRINT to save data and later found they couldn't re-load it and were screwed.
We patched things by adding *PRINT-READABLY* to say "if you're going to
signal an error later in reading, try to accelerate it to output time while
the original data is still prsent and there's half a chance of recovering."
Admittedly, the patch is hard to explain.  But that's its pedigree.  And
it works pretty well if you understand that.
From: Rolf Wester
Subject: Re: Lisp read and writ
Date: 
Message-ID: <3BD66B38.ACB1E67A@ilt.fhg.de>
Hi,

thanks to all who replied. It helped quite a lot.

Rolf Wester