update-instance-for-redefined-class
update-instance-for-redefined-class Standard Generic Function
Syntax:
update-instance-for-redefined-class instance
added-slots discarded-slots
property-list
&rest initargs &key &allow-other-keys
→ {result}*
update-instance-for-redefined-class
Method Signatures:
update-instance-for-redefined-class (instance standard-object)
added-slots discarded-slots
property-list
&rest initargs
Arguments and Values:
instance—an object.
added-slots—a list.
discarded-slots—a list.
property-list—a list.
initargs—an initialization argument list.
result—an object.
Description:
The generic function update-instance-for-redefined-class is not intended to be called by programmers. Programmers may write methods for it. The generic func tion update-instance-for-redefined-class is called by the mechanism activated by make-instances-obsolete.
The system-supplied primary method on update-instance-for-redefined-class checks the validity of initargs and signals an error if an initarg is supplied that is not declared as valid. This method then initializes slots with values according to the initargs, and initializes the newly added-slots with values according to their :initform forms. It does this by calling the generic function shared-initialize
with the following arguments: the instance, a list of names of the newly added-slots to instance, and the initargs it received. Newly added-slots are those local slots for which no slot of the same name exists in the old version of the class.
When make-instances-obsolete is invoked or when a class has been redefined and an instance is being updated, a property-list is created that captures the slot names and values of all the discarded slots with values in the original instance. The structure of the instance is transformed so that it conforms to the current class definition. The arguments to update-instance-for-redefined-class are this transformed instance, a list of added-slots to the instance, a list discarded-slots from the instance, and the property-list containing the slot names and values for slots that were discarded and had values. Included in this list of discarded slots are slots that were local in the old class and are shared in the new class.
The value returned by update-instance-for-redefined-class is ignored.
Examples:
**update-instance-for-redefined-class**
(defclass position () ())
(defclass x-y-position (position)
((x :initform 0 :accessor position-x)
(y :initform 0 :accessor position-y)))
;;; It turns out polar coordinates are used more than Cartesian ;;; coordinates, so the representation is altered and some new ;;; accessor methods are added.
(defmethod update-instance-for-redefined-class :before
((pos x-y-position) added deleted plist &key)
;; Transform the x-y coordinates to polar coordinates
;; and store into the new slots.
(let ((x (getf plist ’x))
(y (getf plist ’y)))
(setf (position-rho pos) (sqrt (+ (\* x x) (\* y y)))
(position-theta pos) (atan y x))))
(defclass x-y-position (position)
((rho :initform 0 :accessor position-rho)
(theta :initform 0 :accessor position-theta)))
;;; All instances of the old x-y-position class will be updated ;;; automatically.
;;; The new representation is given the look and feel of the old one.
(defmethod position-x ((pos x-y-position))
(with-slots (rho theta) pos (\* rho (cos theta))))
(defmethod (setf position-x) (new-x (pos x-y-position))
(with-slots (rho theta) pos
(let ((y (position-y pos)))
(setq rho (sqrt (+ (\* new-x new-x) (\* y y)))
theta (atan y new-x))
new-x)))
(defmethod position-y ((pos x-y-position))
(with-slots (rho theta) pos (\* rho (sin theta))))
(defmethod (setf position-y) (new-y (pos x-y-position))
(with-slots (rho theta) pos
(let ((x (position-x pos)))
(setq rho (sqrt (+ (\* x x) (\* new-y new-y)))
theta (atan new-y x))
new-y)))
Exceptional Situations:
The system-supplied primary method on update-instance-for-redefined-class signals an error if an initarg is supplied that is not declared as valid.
See Also:
make-instances-obsolete, shared-initialize, Section 4.3.6 (Redefining Classes), Section 7.1.4 (Rules for Initialization Arguments), Section 7.1.2 (Declaring the Validity of Initialization Arguments)
Notes:
Initargs are declared as valid by using the :initarg option to defclass, or by defining methods for update-instance-for-redefined-class or shared-initialize. The keyword name of each keyword parameter specifier in the lambda list of any method defined on update-instance-for-redefined-class or shared-initialize is declared as a valid initarg name for all classes for which that method is applicable.
Expanded Reference: update-instance-for-redefined-class
Handling Class Redefinition
update-instance-for-redefined-class is called automatically when a class is redefined and an existing instance is accessed. It receives the instance, a list of added slot names, a list of discarded slot names, and a property list with the old values of discarded slots.
;; First define a class
(defclass position ()
((x :initarg :x :initform 0 :accessor pos-x)
(y :initarg :y :initform 0 :accessor pos-y)))
;; Create an instance
;; (defvar *p* (make-instance 'position :x 3 :y 4))
;; Later, you might redefine the class to use polar coordinates.
;; The system will call update-instance-for-redefined-class
;; on *p* the next time it is accessed.
Defining a :before Method for Migration
A :before method is the recommended way to customize the update. The property-list argument contains old values of discarded slots, accessed with getf.
;; This example shows the pattern for migrating from x/y to rho/theta
;; representation when a class is redefined.
(defclass coordinates ()
((x :initarg :x :initform 0 :accessor coord-x)
(y :initarg :y :initform 0 :accessor coord-y)))
(defmethod update-instance-for-redefined-class :before
((instance coordinates) added-slots discarded-slots plist &key)
;; If x and y were discarded, compute rho and theta
(when (and (member 'x discarded-slots)
(member 'y discarded-slots))
(let ((x (getf plist 'x 0))
(y (getf plist 'y 0)))
(when (slot-exists-p instance 'rho)
(setf (slot-value instance 'rho) (sqrt (+ (* x x) (* y y)))))
(when (slot-exists-p instance 'theta)
(setf (slot-value instance 'theta) (atan y x))))))
The Property List
The property-list is a plist where keys are slot names and values are the old slot values. Only slots that were discarded (removed or changed from local to shared) and had values appear in this list.
;; Conceptual example of the arguments:
;; If a class originally had slots (a b c) and is redefined
;; to have slots (b c d), then:
;; added-slots = (d)
;; discarded-slots = (a)
;; property-list = (a <old-value-of-a>) ; if a was bound