CLHS: Issue GENERALIZE-PRETTY-PRINTER Writeup

#

## Issue GENERALIZE-PRETTY-PRINTER Writeup

    Forum:		Public Review
    Issue:		GENERALIZE-PRETTY-PRINTER
    References:	Loosemore's public review comment #18 (X3J13/92-1318)
    		Section 22.2.1 (Pretty Printer Concepts), p 22-13
    		~/name/ FORMAT directive, p 22-39..22-40
    		PPRINT-DISPATCH, p 22-45..22-46
    		PPRINT-EXIT-IF-LIST-EXHAUSTED, p 22-46
    		PPRINT-FILL (etc), p 22-47
    		PPRINT-INDENT, p 22-48
    		PPRINT-LOGICAL-BLOCK, p 22-49..22-51
    		PPRINT-NEWLINE, p 22-51..22-52
    		PPRINT-POP, p 22-52..22-54
    		PPRINT-TAB, p 22-54
    		PRINT-OBJECT, p 22-55..22-56
    		SET-PPRINT-DISPATCH, p 22-57..22-58
    Category:	CHANGE
    Edit history:	V1, 18 Sept 1992, Sandra Loosemore
    		V2, 18 Sept 1992, Sandra Loosemore
    		  (comments from Dick Waters)
    		V3, 04 Feb 1993, Sandra Loosemore
    		  (fix references)
    Status:		Proposal UNIFY passed 8-3 on letter ballot 93-302.

    Problem description:

      The pretty-printing mechanisms are poorly integrated with the rest
      of the printer.

      Specifically,

      (1) The requirement that objects for which there is no pretty-print
      function defined in *PRINT-PPRINT-DISPATCH* print using the standard
      mechanisms but with *PRINT-PRETTY* bound to NIL (p. 22-15 and 22-45)
      makes it impossible for PRINT-OBJECT methods or DEFSTRUCT
      :PRINT-FUNCTIONS to handle *PRINT-PRETTY* themselves.  This can lead
      to unnecessary duplication of code, as it requires programmers to write
      two different functions to print the same kind of object.

      (2) The behavior of PPRINT-FILL, PPRINT-LINEAR, PPRINT-TABULAR,
      PPRINT-INDENT, PPRINT-LOGICAL-BLOCK, PPRINT-NEWLINE, and PPRINT-TAB when
      *PRINT-PRETTY* is not true is unspecified, although the names imply
      that they are only useful when pretty-printing or that they may bind
      *PRINT-PRETTY*.  Again, to avoid pointless duplication of code, these
      mechanisms should do something reasonable regardless of whether
      *PRINT-PRETTY* is true.

      (3) The order of the "stream" and "object" arguments to
      PPRINT-FILL, PPRINT-LINEAR, PPRINT-TABULAR, functions in pprint
      dispatch tables, and functions used with the ~/name/ format directive
      is backwards with respect to that of other printing functions.

      There are three non-mutually-exclusive proposals here.  Proposal
      UNIFY addresses problems (1) and (2).  Proposal REORDER addresses
      problem (3).  Proposal RENAME changes the names of most of the
      affected functions to reflect the more general utility under proposal
      UNIFY.

    Proposal (GENERALIZE-PRETTY-PRINTER:UNIFY):

      (1) Change the behavior stated in section 22.2.1.4 and in the
      description of PPRINT-DISPATCH to say that if there is no specific
      found in the pprint dispatch table, a function which invokes the
      appropriate PRINT-OBJECT method is used.  Remove the requirement that
      *PRINT-PRETTY* be rebound to NIL.

      (2) Clarify that PPRINT-LOGICAL-BLOCK may be used even when
      *PRINT-PRETTY* is not true.  Remove the requirement that the stream
      cease to behave as a pretty-printing stream if *PRINT-PRETTY* becomes
      bound to NIL.  Clarify that PPRINT-LOGICAL-BLOCK does not locally
      rebind *PRINT-PRETTY*.

      (3) Specify that if *PRINT-PRETTY* is false, the functions PPRINT-FILL,
      PPRINT-LINEAR, and PPRINT-TABULAR print list arguments with a minimum
      of whitespace (i.e., as described in section 22.1.3.8).  Clarify that
      these functions do not locally rebind *PRINT-PRETTY*.

      (4) The draft currently says that PPRINT-NEWLINE, PPRINT-TAB, and
      PPRINT-INDENT do nothing if the stream is not a pretty-printing stream.
      Change this to say they also do nothing if *PRINT-PRETTY* is false.

      (5) Change the description of PRINT-OBJECT to mention the use of
      functions such as PPRINT-FILL to handle *PRINT-PRETTY*, and
      PPRINT-LOGICAL-BLOCK to handle *PRINT-LENGTH* truncation, instead
      of discouraging people from handling these variables properly.

      Rationale:

        This allows you to write a single function that handles both pretty
        and non-pretty printing that can use a single block of code inside
        PPRINT-LOGICAL-BLOCK to print structured objects regardless of whether
        *PRINT-PRETTY* is true.  It also allows you to call the other
        functions without having to make an explicit check to be sure that
        *PRINT-PRETTY* is true, and do something else if it isn't.

    Proposal (GENERALIZE-PRETTY-PRINTER:REORDER):

      (1) Reverse the order of the "object" and "stream" arguments to
      functions in pprint dispatch tables.

      (2) Explicitly state that PPRINT-DISPATCH returns the generic function
      PRINT-OBJECT if there is no matching type specifier in the pprint
      dispatch table.

      (3) Reverse the order of the "object" and "stream" arguments to
      PPRINT-FILL, PPRINT-LINEAR, and PPRINT-TABULAR.  Make the "stream"
      argument optional and default in the usual way for an output stream
      designator, so that the argument list is
        (object &optional stream colon-p at-sign-p).

      (4) Reverse the order of the "object" and "stream" arguments passed
      to functions invoked with the ~/name/ format directive.

      Rationale:

        This removes a pointless inconsistency in the language design and
        makes it a little simpler.

    Proposal (GENERALIZE-PRETTY-PRINTER:RENAME):

      Rename PPRINT-EXIT-IF-LIST-EXHAUSTED, PPRINT-FILL, PPRINT-LINEAR,
      PPRINT-TABULAR, PPRINT-INDENT, PPRINT-LOGICAL-BLOCK, PPRINT-NEWLINE,
      PPRINT-POP, and PPRINT-TAB to PRINT-*.

      Rationale:

        Changing the names makes it more apparent that these functions are
        useful even when *PRINT-PRETTY* is false and that they do not
        rebind *PRINT-PRETTY* to true as PPRINT does.  (Note that this list
        does not include *PRINT-PPRINT-DISPATCH*, PPRINT-DISPATCH, and
        SET-PPRINT-DISPATCH, since these are only relevant when *PRINT-PRETTY*
        is true.)

        Since proposals UNIFY and REORDER make incompatible changes in the
        behavior of these functions, changing their names may be helpful in
        detecting obsolete calls.

    Current practice:

      XP doesn't implement any of these changes.

      Loosemore made most of these changes when rewriting XP into a
      Scheme-like dialect; the Yale Haskell system uses it extensively.

    Cost to implementors:

      Medium.  Making the changes to the printer implementation is
      straightforward, but there are the usual support costs associated
      with making an incompatible change.

    Cost to users:

      This is an incompatible change for people who now use XP, but it's
      easy to fix.  Adoption of proposal RENAME may make it easier to detect
      obsolete uses.

    Cost of non-adoption:

      More work for people writing new code.  Confusion about why
      PRINT-OBJECT methods can't detect when *PRINT-PRETTY* is true.  Risk
      of function for printing when *PRINT-PRETTY* is true getting out of
      sync with function for printing the same object when *PRINT-PRETTY* is
      false.  Risk of people making stupid programming mistakes because they
      can't remember which functions accept arguments in which order.

    Benefits:

      The cost of non-adoption is avoided.

    Aesthetics:

      Making the language simpler and more uniform is generally a good
      thing.

    Editorial impact:

      It would probably take two or three days to make the necessary changes,
      including updating examples.  Loosemore is willing to undertake the
      editorial work.

    Discussion:

      This issue was first raised on the X3J13 mailing list in January 1992
      with the subject "apparent shortcomings with PPRINT interface".

      Loosemore says: I discovered these problems when trying to implement
      the new pretty-printer functionality for the first time for use by the
      Yale Haskell system.  We have several dozen different kinds of structures
      representing AST nodes and wanted to be able to print them reasonably
      for debugging and error messages.  Pushing the detection for
      *PRINT-PRETTY* into the support functions resulted in *major*
      consolidations and simplifications of this code.

      Waters says: I support your proposal strongly.  Please feel free to
      add me to the proposal as a formal supporter.

      John Burger also says he was bitten by the inability to handle
      *PRINT-PRETTY* in PRINT-OBJECT methods, and that he supports this
      proposal.

Copyright 1996-2005, LispWorks Ltd. All rights reserved.