Like most object systems, instances in CLOS have a reference to their class. Unlike most most object systems, CLOS provides a protocol for changing that reference. Normally, this is a pretty insane thing to want to do. It effectively changes the class of the instance and it is pretty unlikely that the instance structure will be compatible with the new class. But there are two situations where you might want to do it anyway:
- When you edit the class definition, you can arrange for the system to dynamically upgrade existing instances to the new class definition. This means you won't have to restart your lisp and rebuild all the instances from scratch. You can just reload the class definition and the instances will be seamlessly upgraded on the fly. This is much more pleasant experience for the developer.
- While you normally don't want to change the class of an instance
at runtime, there are some rare situations where it can make sense. A
good example is the unified table interface. Instances are thin
wrappers around a concrete table implementation. It makes sense to
change a table instance from one concrete implementation to another.
For instance, you might want to change a hash table to a assocation
list. You can simply call
change-class
on the instance.
When the class changes, the representation will be wrong. This is where we add an :after
method to update-instance-for-different-class
:
(defmethod update-instance-for-different-class :after ((previous alist-table) (current plist-table) &rest initargs) (declare (ignore initargs)) (setf (representation current) (alist-plist (representation previous)))) ...etc...
> (defvar *foo* (make-instance 'alist-table :initial-contents '((:a . 420) (:b . 69)))) #<ALIST-TABLE 2 EQL> > (representation *foo*) ((:A . 420) (:B . 69)) ;; But I'd rather have a plist-table > (change-class *foo* 'plist-table) #<PLIST-TABLE 2 EQL> > (representation *foo*) (:a 420 :b 69) ;; And now I'd like a wttree-table > (change-class *foo* 'wttree-table) #<WTTREE-TABLE 2 EQUAL> > (representation *foo*) #(2 NIL :A #(1 NIL :B NIL 69) 420)
Naturally, you have to be judicious in your use of this feature of CLOS. You can easily construct nonsense objects. But some times it makes perfect sense,
No comments:
Post a Comment