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

Issue: LOAD-OBJECTS (Version 1)



This was discussed on the clos and compiler lists.  I thought it would
be a good idea to write it up for discussion and give the cleanup group
a look at it.  I think it's something that fell in the cracks between
these three subcommittees.

Issue:         LOAD-OBJECTS

References:    none

Related issues: none

Category:      ADDITION

Edit history:  Version 1, 2-Jan-89, by Moon (for discussion)

Problem description:

  Common Lisp doesn't provide any way to use an object of a user-defined
  type (defined with DEFCLASS or DEFSTRUCT) as a constant in a program
  compiled with COMPILE-FILE.  The problem is that LOAD has to be able
  to "reconstruct" an equivalent object when the compiled-code file is
  loaded, but the programmer has no way to tell LOAD how to do that.

Proposal (LOAD-OBJECTS:MAKE-LOAD-FORM):
          
  Define a new generic function named MAKE-LOAD-FORM, which takes one
  argument and returns one value.  The value is a form which, when
  evaluated at some later time, should return an object that is
  equivalent to the argument.  The exact meaning of "equivalent"
  depends on the type of object and is up to the programmer who
  defines a method for MAKE-LOAD-FORM.

  Define that COMPILE-FILE calls MAKE-LOAD-FORM on any object that
  appears in a constant and has STANDARD-CLASS or STRUCTURE-CLASS as a
  metaclass.  Define that COMPILE-FILE will only call MAKE-LOAD-FORM
  once for any given object (compared with EQ) within a single file.

  It is unspecified whether LOAD calls EVAL on the form or does some
  other operation that has an equivalent effect.

  Define that an instance of a class defined with DEFCLASS without any
  direct superclasses, or defined with DEFSTRUCT without the :TYPE or
  :INCLUDE options, does not inherit any method for MAKE-LOAD-FORM other
  than possibly a method that only signals an error.

Example:

  (defclass my-class ()
     ((a :initarg :a :reader my-a)
      (b :initarg :b :reader my-b)
      (c :accessor my-c)))
  (defmethod shared-initialize ((self my-class) ignore &rest ignore)
    (unless (slot-boundp self 'c)
      (setf (my-c self) (some-computation (my-a self) (my-b self)))))
  (defmethod make-load-form ((self my-class))
    `(make-instance ',(class-name (class-of self))
                    :a ',(my-a self) :b ',(my-b self)))

  In this example, an equivalent instance of my-class is reconstructed
  by using the values of two of its slots.  The value of the third slot
  is derived from those two values.

  (defclass my-frob ()
     ((name :initarg :name :reader my-name)))
  (defmethod make-load-form ((self my-frob))
    `(find-my-frob ',(my-name self) :if-does-not-exist :create))

  In this example, instances of my-frob are "interned" in some way.
  An equivalent instance is reconstructed by using the value of the
  name slot as a key for searching existing objects.  In this case
  the programmer has chosen to create a new object if no existing
  object is found; alternatively she could have chosen to signal an
  error in that case.

Rationale:

  Only the programmer who designed a class can know the correct
  way to reconstruct objects of that class at load time, therefore
  the reconstruction should be controlled by a generic function.
  Using EVAL as the interface for telling LOAD what to do provides
  full generality.

  A default method, such as one that makes an object whose class has the
  same name and whose slots have equivalent contents, is not supplied
  because this is inappropriate for many objects and because it is easy
  to write for those objects where it is appropriate.

  MAKE-LOAD-FORM has a natural resemblance to PRINT-OBJECT.

Current practice:

  Symbolics Flavors has something like this, but under a different name.
  The name Symbolics uses is not suitable for standardization.

  JonL reports that Lucid is getting more and more requests for this.

Cost to Implementors:

  This seems like only a few one-line changes in the compiled-code
  file writer and reader.

Cost to Users:

  None.

Cost of non-adoption:

  Serious impairment of the ability to use extended-type objects.  Each
  implementation will probably make up its own version of this as an
  extension.

Performance impact:

  None.

Benefits:

  See Cost of non-adoption.

Esthetics:

  No significant positive or negative impact.

Discussion:

  It would be possible to define an additional level of protocol that
  allows multiple classes to contribute to the reconstruction of an
  object, combining initialization arguments contributed by each class.
  Since a user can easily define that in terms of MAKE-LOAD-FORM without
  modifying the Lisp system, it is not being proposed now.

  Any type that has a read syntax is likely to appear as a quoted
  constant or inside a quoted constant.  Pathnames are one example, user
  programs often define others.  Also many implementations provide a way
  to create a compiled-code file full of data (rather than compiled Lisp
  programs), and such data probably include extended-type objects.

  Moon supports this.