[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: printers for structures



> From: john@linus.mitre.org
> 
> Bill St. Clair (bill@cambridge.apple.com) writes:
> 
>   The following works in Macintosh Common Lisp. I haven't tested it
>   anywhere else.
> 
>   (defstruct foo x y)
> 
>   (defvar *print-foos-pretty* nil)
> 
>   (defmethod print-object ((o foo) stream)
>     (if *print-foos-pretty*
>       (format stream "#<A ~s structure with slots ~s: ~s and ~s: ~s>"
>               'foo 'x (foo-x o) 'y (foo-y o))
>       (call-next-method)))
> 
> This works in Allegro 4.1 also.  BUT, in the ANSI draft, structures
> are not required to print via PRINT-OBJECT, although that might seem
> counter-intuitive.

I disagree with this conclusion.  The dpANS says under PRINT-OBJECT
that the printer calls PRINT-OBJECT; PRINT-OBJECT is _not_ called by
user code; that the implementation must provide methods so that all
objects have an applicable method.  Although the spec doesn't
explicitly state that the printer _must_ call PRINT-OBJECT for every
object and subobject printed, one can infer this rather easily from
the above requirements; otherwise the requirement that there always be
an applicable method doesn't is unmotivated.

The matter was certainly clearer in CLtL2, p.852, where the
requirement was explicit.  I don't know why that text was dropped, but
I don't remember any late X3J13 action affecting it so the change must
have been editorial (whether or not intentional).

>      The draft says (p 8-10)
>
>   If :PRINT-FUNCTION [is] not supplied ... then a default printing
>   function is provided for the structure that prints out all its slots
>   using #S syntax. 
> 
>   Supplying :PRINT-FUNCTION ... is equivalent to defining an
>   appropriate method on the PRINT-OBJECT generic function.
> 
> The first paragraph would seem to indicate that every structure has a
> :PRINT-FUNCTION function, whether you define it or not, and thus
> :PRINT-OBJECT methods on an included structure class aren't inherited.
> In the second paragraph, it's not clear what "equivalent" means, as
> Sandra Loosemoore has pointed out in public review comments.  For one
> thing, :PRINT-FUNCTION functions have different argument structure
> than PRINT-OBJECT.

I think this conclusion is amiss as well.  If supplying a
:PRINT-FUNCTION is equivalent to defining a PRINT-OBJECT method on the
class, then inheritance of the method by subclasses is clearly the
natural order of things.

There was some sentiment on X3J13 that the crufty :PRINT-FUNCTION
mechanism would better have been deprecated, but removing it would
have broken lots of existing programs.  Maintaining it is
implementationally messy because the printer has to pass that silly
level argument which the printer now handles completely internally,
but otherwise the automatically-generated PRINT-OBJECT method is just
a closure over the :print-function function.

> This confusion will probably be rectified in the next draft, but for
> now it's yet another example of how hard it is to properly integrate
> new features (CLOS) and old (DEFSTRUCT).

Of course, there is a completely _different_ mechanism that might be
more appropriate to your needs.  You can use SET-PPRINT-DISPATCH to
customize the pretty printer's dispatch.  As Water's writeup points
out, this mechanism allows rapid changes between print setups by
lambda binding *PRINT-PPRINT-DISPATCH*.  Of course, some
implementations might not implement this yet, or you might not be able
to use print with *PRINT-PRETTY* true, or whatever.