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

dependent update protocol



    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.