[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
dependent update protocol
- To: common-lisp-object-system@SAIL.STANFORD.EDU
- Subject: dependent update protocol
- From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
- Date: Mon, 11 Apr 88 15:50 EDT
- In-reply-to: <880411113858.6.GREGOR@SPIFF.parc.xerox.com>
Date: Mon, 11 Apr 88 11:38 PDT
From: Gregor.pa@Xerox.COM
Moon has suggested that the dependents protocol stuff should not be part
of standard-object; rather it should be defined as a separate mixin
since that is what multiple inheritance is for after all. He also
mentioned some problems he had with the way the dependent protocol
worked. He didn't identify those problems, but we had some problems
with it ourselves which we have tried to address.
I believe those possible problems were with the next level up: the way
the updating of subclasses uses this protocol, not with this protocol itself.
I still haven't had time to figure out if those problems are real. However,
since your message didn't address that level at all, we can defer that.
This message outlines a new dependents updating protcol. This protocol
is different from what we had before in several important ways:
- there is a separate mixin for the dependents stuff, that mixin
is used by standard-class to do dependents updating. Users can
use it in their code to particpate in that dependent updating
protocol.
Good.
- There is a mechanism for allowing the modified object to pass
information describing the modification to all the dependents.
This mechanism is designed to allow subclassing to work. That
is, a given class (say standard-class) may use this mechanism to
pass information to its dependents.
Good.
Without specifying the
format of that information, a subclass of standard-class can
augment that information to pass extra information about how
it has been modified.
Actually your example shows that it's not really true that the format
of the information is unspecified. What is specified is that it is a list
with one element for each interested class, in most-specific-first order.
What is unspecified is the format of the list elements.
Dependents of the subclass which expect to
see the augmented information will see it, dependents which do not
expect to see augmented information will see the original
information.
This all seems good except for a couple of minor points:
\Defmeth map-dependents ((instance updatable-object-mixin) function args)
For all dependents of instance, applies function to instance,
the dependent and args.
It's usually better not to try to pass extra args through a mapping
function; instead the function being mapped can be a closure that knows
the extra args. This is more flexible, and is how all eight functions
in CLtL whose names start with "map" work. Thus I would make
map-dependents take only two arguments.
(defmethod reinitialize-instance :around
((object updatable-object-mixin) &rest reinitargs)
(let ((before (apply #'before-reinitialization object reinitargs)))
(call-next-method)
(let ((update-args
(apply #'after-reinitialization object before reinitargs)))
(map-dependents object #'update-dependent object update-args))))
I don't see how this can work if reinitialize-instance changes the set
of dependents. The map-dependents will map over the new dependents, and
any old dependents that were removed will never be updated. Maybe you
can say that remove-dependent, or by convention each caller of it, calls
update-dependent or a variant of it on the dependent being removed.
However, I suspect that is not flexible enough. I know some of our
analogues to this have to start by collecting all the dependents into a
table that is independent of the dependency structure. I don't have an
answer here; I think more thought is required.
This example shows how this protocol might be used. In particular, it
demonstrates how the protocol can be used by a subclass to encapsulate
the information the superclas might pass. All use of this protocol
should be in this style.
If that's true I would prefer to have the style (collecting lists of values
returned by each interested method, and taking them apart again) be enforced
by method combination, instead of leaving it up to each programmer to get
it right.
Also, since the style you propose depends on three methods for three different
generic functions to be kept in sync, and does something unpredictable without
necessarily signalling an error if one of the methods is left out, it doesn't
seem very robust. I would prefer to see either a more abstract data structure
than a list, so that leaving out a method (or forgetting to call cdr) for one
class would not damage the data seen by other class's methods, or else to use
one generic function instead of three, so that all the code for one class would
be in a single place and hence less likely to be out of sync. In the latter
case, this generic function would be called multiple times and one of its
arguments would indicate whether state was being collected or distributed.
My conclusion is that the registration protocol is okay but the updating
protocol needs more thought, although it certainly feels like it's on the
right track.