From: Pascal Bourguignon
Subject: What is not written in CLHS about WRITE and PRINT-OBJECT
Date: 
Message-ID: <87zmb0svct.fsf@thalassa.informatimago.com>
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."

From: Rob Thorpe
Subject: Re: What is not written in CLHS about WRITE and PRINT-OBJECT
Date: 
Message-ID: <1163081666.065553.131430@k70g2000cwa.googlegroups.com>
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.
From: Arthur Smyles
Subject: Re: What is not written in CLHS about WRITE and PRINT-OBJECT
Date: 
Message-ID: <1163085304.397871.37980@i42g2000cwa.googlegroups.com>
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 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).
>
>
> 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."
From: Pascal Bourguignon
Subject: Re: What is not written in CLHS about WRITE and PRINT-OBJECT
Date: 
Message-ID: <87odrgsi4e.fsf@thalassa.informatimago.com>
"Arthur Smyles" <········@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
From: Pascal Costanza
Subject: Re: What is not written in CLHS about WRITE and PRINT-OBJECT
Date: 
Message-ID: <4rgv40Fr1kisU1@mid.individual.net>
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/