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

What is not written in CLHS about WRITE and PRINT-OBJECT

89 views
Skip to first unread message

Pascal Bourguignon

unread,
Nov 9, 2006, 6:38:42 AM11/9/06
to

CLHS WRITE doesn't say much about how lisp objects are printed...
In particular, it doesn't specifies explicitely how PRINT-OBJECT should be used.

CLHS PRINT-OBJECT says that it's "called by the Lisp printer" (and
even precise that it shouldn't be called by the user, but nothing more).


So, with a careless reading, one could expect that defining a
PRINT-OBJECT EQL method on a lisp object whatever it's type, would be
enough to have WRITE (and the PRIN1, PRINC, and PRINT functions that
should call WRITE) call PRINT-OBJECT to print it, or in general, that
defining a PRINT-OBJECT method specialized on the class of any object
would be enough.

But PRINT-OBJECT specifies as ("valid", I guess) method signatures
only STANDARD-OBJECT or STRUCTURE-OBJECT for its first argument. In
consequence, it's implementation dependant whether PRINT-OBJECT is
called on objects that are neither STANDARD-OBJECT or STRUCTURE-OBJECT,
including any object of a builtin class, like FUNCTION.

This is surprizing, given "22.1.3 Default Print-Object Methods", but
"11.1.2.1.2 Constraints on the COMMON-LISP Package for Conforming
Programs" actually specifies undefined consequences when overriding
PRINT-OBJECT for any _standardized_ class like FUNCTION (point 19).

Therefore we cannot use PRINT-OBJECT to define any fancy output for
random lisp objects, only for our own user defined (standard and
structure) classes.


I would have liked to get the behavior of ACL as standard behavior :-(

% clall '(setf *print-readably* nil)'\
'(defvar *f* (lambda (x) x))'\
'(defmethod print-object ((self (eql *f*)) stream)
(format stream "#<An identity function>") self)'\
'(progn (princ *f*) (print *f*))'
========================================================================
CLISP 2.39 (2006-07-16) (built 3364813332) (memory 3364813914)


Evaluation of
(SETF *PRINT-READABLY* NIL)
produced nothing on *STANDARD-OUTPUT*
produced nothing on *ERROR-OUTPUT*
produced the following values:
--> NIL


Evaluation of
(DEFVAR *F* (LAMBDA (X) X))
produced nothing on *STANDARD-OUTPUT*
produced nothing on *ERROR-OUTPUT*
produced the following values:
--> *F*


Evaluation of
(DEFMETHOD PRINT-OBJECT ((SELF (EQL *F*)) STREAM)
(FORMAT STREAM "#<An identity function>") SELF)
produced nothing on *STANDARD-OUTPUT*
produced nothing on *ERROR-OUTPUT*
produced the following values:
--> #<STANDARD-METHOD ((EQL #<FUNCTION :LAMBDA (X) X>) #<BUILT-IN-CLASS T>)>


Evaluation of
(PROGN (PRINC *F*) (PRINT *F*))
produced the following *STANDARD-OUTPUT* (lines excluded):
------------------------------------------------------------------------
#<FUNCTION LAMBDA (X) X>
#<FUNCTION :LAMBDA (X) X>
------------------------------------------------------------------------
produced nothing on *ERROR-OUTPUT*
produced the following values:
--> #<FUNCTION :LAMBDA (X) X>

========================================================================
[... other implementations are similar to clisp ...]
========================================================================
International Allegro CL Free Express Edition 8.0 [Linux (x86)] (Jun 6, 2006 16:01)


Evaluation of
(SETF *PRINT-READABLY* NIL)
produced nothing on *STANDARD-OUTPUT*
produced nothing on *ERROR-OUTPUT*
produced the following values:
--> NIL


Evaluation of
(DEFVAR *F* (LAMBDA (X) X))
produced nothing on *STANDARD-OUTPUT*
produced nothing on *ERROR-OUTPUT*
produced the following values:
--> *F*


Evaluation of
(DEFMETHOD PRINT-OBJECT ((SELF (EQL *F*)) STREAM) (FORMAT STREAM "#<An identity function>") SELF)
produced nothing on *STANDARD-OUTPUT*
produced nothing on *ERROR-OUTPUT*
produced the following values:
--> #<STANDARD-METHOD PRINT-OBJECT ((EQL #<Interpreted Closure (unnamed) @ #x716de3d2>) T)>


Evaluation of
(PROGN (PRINC *F*) (PRINT *F*))
produced the following *STANDARD-OUTPUT* (lines excluded):
------------------------------------------------------------------------
#<An identity function>
#<An identity function>
------------------------------------------------------------------------
produced nothing on *ERROR-OUTPUT*
produced the following values:
--> #<An identity function>

========================================================================

--
__Pascal Bourguignon__ http://www.informatimago.com/

"Logiciels libres : nourris au code source sans farine animale."

Rob Thorpe

unread,
Nov 9, 2006, 9:14:26 AM11/9/06
to
Pascal Bourguignon wrote:
> CLHS WRITE doesn't say much about how lisp objects are printed...
> In particular, it doesn't specifies explicitely how PRINT-OBJECT should be used.
>
> CLHS PRINT-OBJECT says that it's "called by the Lisp printer" (and
> even precise that it shouldn't be called by the user, but nothing more).

This is the kind of situation a CDR could be useful for.

Arthur Smyles

unread,
Nov 9, 2006, 10:15:04 AM11/9/06
to
It is not obvious, but printing is directed by the
pprint-dispatch-table and not method specialization. The only time it
uses print-object is when there is no entry in that table.

See
http://www.lispworks.com/documentation/HyperSpec/Body/22_bad.htm

Arthur

Pascal Costanza

unread,
Nov 9, 2006, 10:17:19 AM11/9/06
to
Pascal Bourguignon wrote:
> CLHS WRITE doesn't say much about how lisp objects are printed...
> In particular, it doesn't specifies explicitely how PRINT-OBJECT should be used.
>
> CLHS PRINT-OBJECT says that it's "called by the Lisp printer" (and
> even precise that it shouldn't be called by the user, but nothing more).

There is a mention of pretty printing taking precedence over
print-object in 22.2.1.4 in the HyperSpec. Specifically, the default
value of *pretty-print* is implementation dependent, which means that it
is not clear whether print-object is used by default or not (IIUC). Play
around with *print-pretty* and *print-pprint-disptach* and see what happens.

> So, with a careless reading, one could expect that defining a
> PRINT-OBJECT EQL method on a lisp object whatever it's type, would be
> enough to have WRITE (and the PRIN1, PRINC, and PRINT functions that
> should call WRITE) call PRINT-OBJECT to print it, or in general, that
> defining a PRINT-OBJECT method specialized on the class of any object
> would be enough.
>
> But PRINT-OBJECT specifies as ("valid", I guess) method signatures
> only STANDARD-OBJECT or STRUCTURE-OBJECT for its first argument. In
> consequence, it's implementation dependant whether PRINT-OBJECT is
> called on objects that are neither STANDARD-OBJECT or STRUCTURE-OBJECT,
> including any object of a builtin class, like FUNCTION.

No, that's not what it means. It only means that there are two
predefined methods for standard-object and structure-object. This is
useful information when you want to define your own methods.
Specifically, it means that you can perform supercalls in methods on
structs and classes.

> This is surprizing, given "22.1.3 Default Print-Object Methods", but
> "11.1.2.1.2 Constraints on the COMMON-LISP Package for Conforming
> Programs" actually specifies undefined consequences when overriding
> PRINT-OBJECT for any _standardized_ class like FUNCTION (point 19).
>
> Therefore we cannot use PRINT-OBJECT to define any fancy output for
> random lisp objects, only for our own user defined (standard and
> structure) classes.

Yes, this restriction is defined because otherwise it's not clear what
happens when two different, possibly third-party libraries define
methods for the same predefined classes or instances thereof. I think
the rule for eql specializers is somewhat too strict, but there you go.

If you need user-defined methods on functions and have the CLOS MOP
available, you can of course define a subclass of
standard-generic-function just for this purpose.

> I would have liked to get the behavior of ACL as standard behavior :-(

I think toggling *pretty-print* should help (but I'm not 100% sure).


Pascal

--
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/

Pascal Bourguignon

unread,
Nov 9, 2006, 11:24:33 AM11/9/06
to
"Arthur Smyles" <atsm...@earthlink.net> writes:

> It is not obvious, but printing is directed by the
> pprint-dispatch-table and not method specialization. The only time it
> uses print-object is when there is no entry in that table.
>
> See
> http://www.lispworks.com/documentation/HyperSpec/Body/22_bad.htm

Even adding (setf *print-pretty* nil), I get the same results in all
the tested implementations.

But I'll have to study CL pretty-printing...

--
__Pascal Bourguignon__ http://www.informatimago.com/

Until real software engineering is developed, the next best practice
is to develop with a dynamic system that has extreme late binding in
all aspects. The first system to really do this in an important way
is Lisp. -- Alan Kay

0 new messages