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

Re: Redefining Classes



     Date: Mon, 28 Sep 87 22:18 EDT
     From: "David A. Moon" <Moon@scrc-stony-brook.arpa>
     
     Summary: When redefining a class causes instances to be updated can be
     implementation-dependent.  (update-from-obsolete-instance instance
     added-slot-names removed-slot-names removed-bound-slot-values); the
     primary method uses initforms to initialize the slots whose names are
     listed in added-slot-names.  update-from-obsolete-instance is called no
     later than the first slot read or write after the class is redefined.
     The retained slot values are already in place when
     update-from-obsolete-instance is called.  Those are my opinions.
     

     
     	I have two problems with [update-obsolete-instance].
     	The easy problem is that I
     	don't like the name update-obsolete-instance, because the instance
     	doesn't really seem obsolete to me.  One idea is to take an analogy
     	to class-changed and call it class-redefined.  In Flavors we call
     	it transform-instance, but it doesn't have quite the same
     	semantics.  It's likely that someone can think of a better name
     	than any of these.
         We could call it update-from-obsolete-instance, or
         conform-instance-to-class.  Since it takes ans instance as an argument,
         I don't like names like class-redefined -- which seems to focus on the
         class.
     
     Good point.  update-from-obsolete-instance appeals to me, although it
     might be thought to imply that two instances are involved.

We could call it update-instance-structure.  We talked about the structure
of an instance being changed in the writeup.
     
     	Much more important, I can't implement the specification that
     	the slots are initially uninitialized and then they are filled in
     	from values saved in a property list.  There are two problems, one
     	obvious and one subtle.  The obvious problem involves slots that
     	were unbound originally; since there is no Lisp value that means
     	"unbound", there is nothing that can be put into the property list
     	for these slots.  But if we don't put any entry in the property
     	list, then the desired feature that the method can tell which slots
     	were added or removed is lost; these slots look like they were
     	added, even though they weren't.
       
         We could designate such a value (make it be the value of a globally
         accessible variable).  Then putting such a value in  a slot would be
         equivalent to making it unbound.  I can hear the ARGHHH from here, but
         it does make accessible something that we are having to make
         programmable (e.g. SLOT-MAKUNBOUND ...).  Aside from matters of taste
         (and I could be convinced on this fairly easily), why is it you could
         not implement this -- is there a particular tradeoff that you are not
         being explicit about?
     
     It doesn't work to have a magic Lisp object that means "unbound" when it's
     the value of a slot, because then you can never talk about that value in
     any way that involves putting it into a slot.  If you think that's a matter
     of taste, the other answer is that my hardware has the unbound slot value
     built into it, and it would cost me a couple million dollars to change it.
     Here we have both the rarified philosophical argument and the businesslike
     pragmatic argument.

As Moon says, "unbound" is a value, but not a lisp object.  I would
oppose a proposal saying that we can pass it around and storing it into
a slot.  Note that SLOT-MAKUNBOUND would not implemented using CLtL
primitives, but lower level ones that don't see lisp objects but bits.
     
     
     To my way of thinking it is philosophically inconsistent to have different
     rules for whether a slot's value is changed when the class is redefined,
     depending on slot-boundp.  At this level, "unbound" should be treated like
     just another value.  I hope you don't think this is too inconsistent with
     what I said just above: "unbound" is a slot value, but it is not a Lisp
     object.
     
     I think it's better to do things like filling in previously unbound
     slots in old instances with update-from-obsolete-instance (or whatever
     name we choose) methods.  

I agree.  If you want to reinitialize some slot, modify the method for
"update-from-obsolete-instance (or whatever name we choose)" and call
MAKE-INSTANCES-OBSOLETE.
     
     	The subtle problem involves some language extensions that we
     	have, allowing slots to have contents that cannot be expressed as
     	Lisp values in a property list.  For instance, there is a mechanism
     	similar to Prolog logic-variables which allows two slots to be
     	linked together. This linkage has to be preserved in the face of
     	class redefinition.
         Can such linked values only be used inside of objects, and not within
         lists?  I though inivisible pointers can be used anywhere.  I don't
         understand what the assumptions underlying this extension are.
     
     They can be used in lists, but the point is that care needs to be exercised
     when moving them around.  The net effect is that the code that moves slot
     values from one piece of memory to another, when an instance has to have
     new memory allocated for it, can't be written portably in our system.  But I 
     don't see why anyone would want a portable version of it.

I hadn't though of that.  This is true, we must preserve those
structures.  The problem is the same as with unbound slots, invisible
pointers are not lisp objects.

	For these reasons, I believe it is better to specify that the
	slot values are conveyed from the old structure of the instance to
	the new structure by the low-level implementation, not by a
	user-replaceable method.  Thus when the generic function
	update-obsolete-instance is called, all slots that existed in the
	old class definition, and existed as instance slots in the new
	class definition, already have their values, as the same low-level
	bits.  I can't see any need for even a meta-user to replace this
	with something else.

Shouldn't CHANGE-CLASS & CLASS-CHANGED changed the same way for the same
reasons?
     
     	    Because update-obsolete-instance is user code, its
     	    operation can be seen by the user; but the model that CLOS
     	    supports is that as far as the user can tell, all the existing
     	    instances of a class are updated as soon as the class
     	    redefinition happens.  This implies that the user must define a
     	    method for update-obsolete-instance before redefining a class.
     	    Implementations are free to delay the conversion of existing
     	    instances (for example, to method call or slot access time),
     	    but users should never be able to see the untransformed
     	    instance.
     
     	We're going to have to specify this a little more precisely, I
     	suspect. We should specify when is the latest time that an
     	implementation can call update-obsolete-instance, and then say that
     	it is permitted to call it any time earlier (after the class has
     	been redefined).  I now believe that the latest time can simply be
     	the time any of the four slot access and modification functions (or
     	internal equivalent) is called, in spite of all the flaming against
     	this we engaged in while discussing Danny's proposal at the meeting
     	last week.
     
         Agreed.
     
     I'd like to hear Patrick's opinion on this timing issue before I have much
     confidence that we have figured it out.

It's OK with me. It is important that all the metaclass primitive that
we specify have to work the same way. The meta-user  should not get hold
of a value coming from a non-updated instance. 


Patrick.