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

re: defstruct extensions



    Date: Tue, 27 Oct 87 09:33:23 PST
    From: goldman@vaxa.isi.edu

    The recently discussed extensions to DEFSTRUCT are reasonable and
    needed improvements.  But I dissent from the proposal(s) for controlling
    printing, which seem like they require the use of a sledgehammer to
    crack an egg -- i.e., rebinding a special variable with dynamic effect
    on printing of ALL structure instances (or even all instances of a
    given class), including those embedded withing fields of other
    instances, when what is wanted, if Corkill's example is
    representative, is a finer control over a particular instance of printing.
[I can't parse this last over-long sentence.]

The default structure printing is no egg.  It is a large boulder
that someone dropped on us.  The right technology to deal with
it is not a sledgehammer, but dynamite.  The one and only thing
I want to have to do with the default structure printer is to
*MAKE* *IT* *GO* *AWAY*!

The one exception to this is if I indicate that I am doing output
that is to be read by a program.  The default structure printer
is something only a program could love.

The issue of how structures print is closely related to the
issue of separating the use of printer control variables for
controlling program communication from the use of printer
control variables as user-interface parameters.

In this vein, I have another proposal to make:

*PRINT-STRUCTURE-CONTENTS*
  :FORCE-READABLE == force the now "standard" syntax.
  T == use the now "standard" syntax unless a printer is
       defined.
  NIL (the recommended default at top level) = use the
      #<...> syntax unless a printer is defined.

[Feel free to add finer-grain control if desired, but this
 is definitely the level I would want to control this at.]

PRINTING-RANDOM-OBJECT ((object stream &key (typep t) (unique-id t))
			&body body)
  Used in print functions, this takes care of printing the standard
  part of non-readable objects.  If *PRINT-FOR-READ* is T (see below),
  it signals an error.  The body is responsible for printing all
  of the stuff in the middle, to identify the particular structure.
  :TYPEP NIL suppresses the type name at the start (leaving that
  responsibility to the body), and :UNIQUE-ID NIL suppresses the
  number at the end.

*PRINT-ESCAPE*
  NIL == use the printer control variables.
  T == use the printer control variables.
  :FOR-READ = signal an error if PRINTING-RANDOM-OBJECT is called.
  :FOR-READ-FORCE = skip print functions, and signal an error if
    PRINTING-RANDOM-OBJECT is called (say, by the system-supplied
    printer for a compiled function).
    

WITH-IO-ENVIRONMENT ((&Rest IO-keywords &KEY &ALLOW-OTHER-KEYS)
		     &Body body)
  Set up the IO parameters to allow programs to communicate.
  Binds all IO parameters (including any defined by local
  extensions to CL) to produce the standard results.  (*PRINT-ESCAPE*
  is bound to :FOR-READ, *PRINT-STRUCTURE-CONTENTS* is bound to
  T).

  Any IO-keywords supplied override the standard values.  For example,
  an application may which to say:
  (WITH-IO-ENVIRONMENT (:PACKAGE "MY-DATABASE" :BASE 8.)
     (PRINT DATABASE STREAM))

[Actually, I really think that printer control should be on a per-stream
basis, and the printer control variables should just serve as defaults
when creating a stream.  But I don't see how to change that at this late
date.]

DEFAULT-PRINT-STRUCTURE (object stream print-depth)
  Print a structure in the now-standard manner.

To take your example and recast it slightly:
  (defstruct
	(employee
	 (:print-function
	  (lambda (employee stream print-depth)
	    ;; This print function won't be called if *PRINT-ESCAPE*
            ;; is :FOR-READ-FORCE.
	    (case *print-escape*
	      (:for-read
		(default-print-structure employee stream print-depth))
	      (otherwise
		(format stream "{Employee: ~A}"
			(employee-name employee))))))))

(One flaw in your example was that *PRINT-PRETTY* is only supposed
to control simple changes like whitespace and 'FOO vs (QUOTE FOO).)

Implementations would be allowed to default the printer flags
with somewhat more latitude than they are now.  For example:

*print-case*, *print-level*, *print-length*, *print-array*,
*print-structure-contents*.

In addition, an implementation may provide other flags, such
as *PRINT-ARRAY-LENGTH*, (a maximum size to print using the
readable syntax for arrays), and these must be bound by
WITH-IO-ENVIRONMENT to values to producing the standard syntax.

Any program writing data for use by other programs which does
not use WITH-IO-ENVIRONMENT is in error.  (Currently, any program
which doesn't simulate WITH-IO-ENVIRONMENT by hand, is going to
break whenever any user sets any control variables for whatever
reason.