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

MAKE-LOAD-FORM can handle circularities [was Compilation implications]



    Date: Tue, 10 Jan 89 19:03:49 PST
    From: jrose@Sun.COM (John Rose)

    Simply allow the second form to contain a reference to the object
    being dumped.

    Neat, yes?  File-level EQ preservation works to restore the embedded
    object reference "for free".

Right.  You are so smart!

    And, while we're at it, give the programmer a break, and let the second
    form be optional.

That was always the intention.  Complex capabilities shouldn't make doing
simple things harder.

    Here's a more complete description of these ideas:

I pretty much agree with your description.  I still hope to find time
to write a second version of the proposal, which will incorporate what
you said, except that I will try to write it in less implementation
oriented terms and more language oriented terms.

    Define a generic function MAKE-LOAD-FORM which takes one argument and
    returns one or two values.  This function is called whenever
    COMPILE-FILE needs to dump an object whose class is of type
    STANDARD-CLASS or STRUCTURE-CLASS.  (Call these types "user defined".)
    It returns one or two Lisp forms, which when passed at load time to EVAL
    will construct an object which is, in some class-specific sense,
    "equivalent" to the original object.

    Call the first form returned by MAKE-LOAD-FORM the "allocator", and the
    second form the "initializer".

    The allocator must wholly or partially build the reconstructed object,
    and return an ordinary Lisp reference to it.  The initializer, if
    supplied and non-null, must finish any initialization required by the
    object's class.  It is an error if the result of this second form is not
    EQ to the result of the first.

If you remove this seemingly useless error check, you don't have to special
case NIL as a second value.  (EVAL NIL) never hurts.

    Both the allocator and initializer are dumped to and restored from the
    binary file by COMPILE-FILE, by the usual means.  It is expected that
    they will consist of list structure, possibly with object of user-defined
    type at the fringe.

    The allocator must be dumpable without reference to the original object.
    That is, in the process of dumping the original object, the dumper must
    not be called upon to output the original object again until the allocator
    has been completely dumped.

    The initializer may contain references to arbitrary objects.  In
    particular, it will typically contain a reference to the original
    object.  Because all references to a given object in a compiled file
    remain EQ across load, this can be reliably ensured simply by having
    MAKE-LOAD-FORM return a reference to the original object embedded in
    its second argument.

    While the initializer form is being read in, the reconstructed object is
    possibly in an uninitialized state, analogous to the state of an object
    between the time its reference has been created by ALLOCATE-INSTANCE
    and it has been processed fully by INITIALIZE-INSTANCE.  Implementors
    must take care in manipulating objects referenced by allocator and
    initializer forms, as they would in manipulating partially initialized
    objects inside INITIALIZE-INSTANCE.

    (Think of the allocator as creating a reference to a chunk of storage,
    which stands in for the object until such time as the initializer can
    really create it.  Meanwhile, the reference can be stored in other data
    structure, and such stored references will become fully valid when the
    object is finally initialized.)

    Note that it is possible for uninitialized objects to appear in either
    of the allocator or initializer forms, but when the loading process
    completes, all initalizers will have been run.

    A programmer of a certain class may elect to return a null initializer,
    and perform all initialization in the allocator (which could then be a
    simple call to MAKE-INSTANCE).  In this case, some circular data
    structures involving that class will not be dumpable.  However, such
    "simply dumped" classes may take part in circularities, as long as any
    such a circularity includes at least one object which returns two values
    for MAKE-LOAD-FORM, and whose allocator form breaks the circularity by
    omitting all references to the next object in the circle.  Therefore,
    not all classes need support the two-phase dumping protocol.

    (Roughly speaking, in order to win, you need to have "enough" classes
    with "small" allocator forms.)

    Example:
	    (defclass tree-with-parent () (parent children))
	    (defmethod make-load-form ((x tree-with-parent))
	      (values
		`(allocate-instance (class-of x) :children ',(slot-value x 'children))
		`(initialize-instance ',x :parent ',(slot-value x 'parent))))

The example needs some debugging.