[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
putting CLOS objects in binfiles
- To: Moon@STONY-BROOK.SCRC.Symbolics.COM, Bobrow.pa@Xerox.COM
- Subject: putting CLOS objects in binfiles
- From: jrose@Sun.COM (John Rose)
- Date: Mon, 18 Jul 88 13:06:16 PDT
- Cc: common-lisp-object-system@SAIL.STANFORD.EDU
- Cc: jrose@Sun.COM
- In-reply-to: David A. Moon's message of Fri, 15 Jul 88 17:07 EDT <19880715210732.7.MOON@EUPHRATES.SCRC.Symbolics.COM>
Date: Fri, 15 Jul 88 17:07 EDT
From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
Date: Fri, 15 Jul 88 12:42:03 PDT
From: jrose@Sun.COM (John Rose)
It's a shame that there's no provision in CLOS for
saving objects in binfiles.
...
Here's essentially what's needed: A generic function
(called, say, RECONSTRUCTOR-FORM) which returns a
Lisp form to evaluate to reconstruct any given
object.
This is fine. It's how Flavors does it, so there is some
precedent. The only problem with this technique is that it
doesn't cope well with circular structures, which can only
be handled by separating creation of the objects from filling
them in (and even that doesn't work in general, for reasons
too complicated to get into here).
...
OK, I'd like to create a proposal. I understand my hallmate
Cris Perdue is thinking about binfiles, so I'll talk with him
some first.
To deal with circularities, one can separate the object creation
protocol into two passes, one to create a reference to an uninitialized
object (which can be used to plug into other structures), and a second
pass to initialize the object itself. You say there are in
general problems here, and I imagine you are referring to
the window between the two passes, when the object can be
referenced, but might not yet contain valid data. Do you
think this problem can be addressed adequately as follows:
At dump time, if circularities are detected, the target
of a back-arc (which will need to be created in two passes
at load time) is passed to a generic function (named, e.g.,
CIRCULAR-RECONSTRUCTOR-FORMS) which either generates parameters
for the two load time passes, or signals an error at dump time.
This would allow a class to disallow all or some circularities,
or handle them in a class-specific manner, by gaining some control
over the window between the two load time passes. An object
in the inter-pass window could even have a different class; pass 2
could perform a CHANGE-CLASS.
Also, let me make another stab at a default behavior for dumping:
Use the PRINT-OBJECT printer, and save the string the binary file.
Proper use of a *PRINT-READABLY* flag would be required to detect errors,
and recursive calls to PRINT-OBJECT would have to transfer
control to the binary dumper (leaving a #<n># or similar
notation in the object's string). The advantage of this
default is that the class writer need only code a readable
PRINT-OBJECT representation, and not worry about binary files
explicitly.
Here's my immediate problem: I want to build objects
which represent predicates in a special purpose query
language, and I want them to be uniquified, like pathnames
on the Lisp Machine. (They cache things like compiled Lisp
code, so it's expensive to build new copies.) Such things
do not dump properly, and even if a simple patch were to
be applied (say, to dump a class symbol instead of a class),
a simple-minded load routine would not uniquify them.
I'm not sure that anything in Common Lisp requires that multiple
references to a single object, in a file being compiled, do not
turn into multiple objects when the file is loaded.
Symbols load as single objects. And on the Lisp Machine (last
time I looked) pathnames were interned in the same way.
I think this is done because symbols and pathnames are
used as names, or references for other objects, and making
them EQ makes for fast comparison, and allows referencing
parties to make shared annotations on the name object.
You might have
to address this in an implementation-dependent way unless the
definition of Common Lisp were changed to require this explicitly.
I think most implementations do guarantee object identity within
a single COMPILE-FILE, even though they're not required to.
This is not a CLOS issue, it applies to all objects for which EQ
is defined.
I'm willing to guarantee object identity myself, if I can only
get control whenever the system thinks it wants to cons one of
my objects, and intern it. Something like this:
(LET ((TABLE (MAKE-HASH-TABLE :TEST 'EQUAL)))
(DEFMETHOD MAKE-INSTANCE ((EQL 'MYCLASS) &KEY X Y)
(LET ((PARAMS (LIST X Y)))
(OR (GETHASH PARAMS TABLE)
(SETF (GETHASH PARAMS TABLE)
(CALL-NEXT-METHOD))))))
Date: 15 Jul 88 17:08 PDT
From: Bobrow.pa@Xerox.COM
In Loops, the way we solved this problem was to provide each savable object a
unique identifier. This UID was constructed from some representation of the
machine of ceation and the time of creation. An object knows its UID, and from
the UID one can find the object. For any object, the form that was dumped
includes its UID, as well as its contents. References from a dumped object to
another object contain a form which reconstructs the pointer to object referred
to, but does not try to reconstruct its contents.
Wow! That's neat stuff. It shows how far we've come that solutions
to the problem of object identity within a single Lisp session are taken
for granted (reread the CLtL chapter on packages if you think it's
no problem) and the current research is into defining and maintaining
uniqueness across much wider domains, such as all machines and times
in some space.
But all I wanted (this time) was uniqueness across a session, and
some sort of transportable printed representation, like symbols or LispM
pathnames.
-- John