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."
This is the kind of situation a CDR could be useful for.
See
http://www.lispworks.com/documentation/HyperSpec/Body/22_bad.htm
Arthur
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/
> 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