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

RE: Extending DEFSTRUCT



Kevin Gallagher has twice proposed what I believe is a well-reasoned and
much needed extension to defstruct-defined structures.  About a year ago
his first proposal received one favorable response on the list and died.
His most recent reposting (in response to the recent discussion of
defstruct) has received no responses.

[The proposed extensions were:

  STRUCTURE-SLOT structure slot            {a valid SETF form}    [Function]
  STRUCTURE-SLOT-NAMES structure-type                             [Function]
  MAKE-STRUCTURE structure-type keyword-1 value-1 ...             [Function]
  STRUCTURE-OPTION structure-type option                          [Function]
  STRUCTURE-SLOT-OPTION structure-type slot option                [Function]
  DEFSTRUCTP symbol                                               [Function]
]

I would like to believe that the lack of responses to Kevin's extensions
(or any further discussion of defstruct and structures) indicated an
implicit endorsement of a useful proposal.  Anyone who builds portable
tools, layered systems, or extensible languages that rely on defstruct-
defined structures needs these capabilities.  They are relatively easy for
an implementer to provide, they are impossible for a user to write in an
implementation independent manner, they do not violate the storage
abstraction provided by defstruct, and they elevate structures to the same
level of ``official'' support for interrogatives as arrays.  (I can ask for
the dimensions of an array but not the slot-names of a structure?)  I
heartily endorse his proposal.

In fact, I would add two more EXTENSIONS that I have found frustratingly 
absent from the CL specifications.

---------------------------------------------------------------------------

Add'l extension 1:

There is no way in the type system to detect if an object is a structure
whose structure name has been added to the CL data-type system (i.e.,
defined with no :TYPE option).  The following would provide this ability:

  STRUCTUREP object                                               [Function]

Returns true if object is a structure whose structure name has been added
to the CL data-type system; nil otherwise.

---------------------------------------------------------------------------

Add'l extension 2:

I often use defstruct print functions to print structures in a palatable
format for human eyes.  I also want them printed using the normal #S()
notation when writing them to a database file.  The following is a tempting
way of writing such print functions:

(defun EMPLOYEE-DEFSTRUCT-PRINTER (employee stream print-depth)

  (declare (ignore print-depth))
  (cond

    ;; Less-than-pretty printing requested ::
    ((and (not *print-pretty*) *print-escape*)
     (prin1 employee))

    ;; Pretty printing requested ::
    (t
     (format stream "{Employee: ~A}" (employee-name employee)))))

Of course, this will NOT work because there is no way of disabling the
employee print function during the printing performed by prin1.  Instead, I
am forced to duplicate the printing of the default #S() format myself.  (I
might be tempted to write a generic print-structure-in-default-format
function, but of course I would need the extensions proposed by Gallagher
to do that!)  So instead of prin1, I must write:
        
     (format stream
             "#S(EMPLOYEE :SOCIAL-SECURITY-NUMBER ~S ~
                 :NAME ~S :HOURLY-RATE ~S ...)"
             (employee-social-security-number employee)
             (employee-name employee)
             (employee-hourly-rate employee) ...))

Explicitly naming each slot in the structure (and remembering to change the
printer if a slot is added or deleted from the defstruct definition).

Ugh!!  The abstraction provided by defstruct has been lost (as well as
whatever efficient default printing of structures has been provided by the
implementers).

A simple parameter *INHIBIT-DEFSTRUCT-PRINTERS* to control whether or not
printing uses or ignores the defstruct print function would save the day!
Voila:

(defun EMPLOYEE-DEFSTRUCT-PRINTER (employee stream print-depth)

  (declare (ignore print-depth))
  (cond

    ;; Less-than-pretty printing requested ::
    ((and (not *print-pretty*) *print-escape*)
     (let ((*inhibit-defstruct-printers* t))
       (prin1 stream employee)))
    
    ;; Pretty printing requested ::
    (t
     (format stream "{Employee: ~A}" (employee-name employee)))))

---------------------------------------------------------------------------

Structures have become such an important component of CL.  It's unfortunate
that the lack of a few simple extensions seriously hamper using them.

-- Dan Corkill
   cork@cs.umass.edu