I'm trying to readably print a common lisp structure to a file so it can be read back in later. It appears SBCL has some rather sophisticated built-in facilities for readably printing complex objects, which may obviate having to write specialized print-object methods.
Is it possible that my structure's own :print-function
is interfering with *print-readably*
?
(defstruct (problem-state (:conc-name problem-state.) (:print-function print-problem-state) (:copier nil))
"A planning state including the current propositional database."
(name nil :type symbol) ;last action executed
(instantiations nil :type list) ;from last action effect
(happenings nil :type list) ;a list of (object (next-index next-time next-direction)) pairs
(time 0.0 :type real)
(value 0.0 :type real)
(heuristic 0.0 :type real)
(idb (make-hash-table) :type hash-table) ;integer hash table of propositions
(hidb (make-hash-table) :type hash-table)) ;integer table for happening events
When executing
(defun save (object file)
"Saves an object to a file so it can be read in later."
(with-open-file (out-stream file :direction :output)
(let ((*print-readably* t))
(pprint object out-stream))))
for a structure instance, the result is human readable, but not lisp readable.
Do I need to somehow disable the :print-function
(if this is the problem)?
If you provide a :print-function
or :print-object
option to defstruct
, then the printer you designate will be used to print objects of that class. It's the responsibility of that function to deal with the printer control variables correctly. In particular this means that if *print-readably*
is true it must either print the object readably or signal an error if it's not willing or unable to do so: it should not simply print the thing unreadably, and still less should it bind or assign to *print-readably*
or anything like that.
print-unreadable-object
can help you get this behaviour correct:
(defstruct (foo
(:print-function (lambda (f s d)
(declare (ignore d))
(print-unreadable-object (f s :type t :identity t)
...))))
...)
will behave correctly, as print-unreadable-object
is defined to signal a suitable error if *print-readably*
is true.
If you want to be able to print a structure readably if need be but unreadably otherwise it is relatively hard to do this using the :print-function
or :print-object
mechanisms. Your function clearly doesn't get this correct: I suspect few do.
Fortunately there is an easy answer, which is not to use these options, but define methods on print-object
:
(defstruct foo
x)
(defmethod print-object ((f foo) s)
(if *print-readably*
(call-next-method)
(print-unreadable-object (f s :type t :identity t)
(format s "x = ~A" (foo-x f)))))
And now
> *print-readably*
nil
> (let ((*print-readably* t))
(print (make-foo)))
#S(foo :x nil)
#<foo x = nil 8010058923>
Of course all the :print-function
and :print-object
mechanisms do is define stylized methods on print-object
for you. From defstruct
:
The
:print-function
and:print-object
options specify that aprint-object
method for structures of type structure-name should be generated.
Before CLOS (when :print-object
didn't exist) :print-function
did something in a more deeply magic way, but that's all been greatly simplified by CLOS.