Is there a general method for cloning CLOS objects?

I'm looking for a way to clone CLOS objects shallowly, so the created object will have the same type with the same values โ€‹โ€‹in each slot, but a new instance. The closest I found is the standard copy-structure function, which does this for structures.

+6
source share
2 answers

There is no standard predefined way to copy CLOS objects at all. If possible, itโ€™s not at all trivial to provide a reasonable default copy operation that does the right thing (at least) most of the time for arbitrary objects, since the correct semantics vary from class to class and from application to application. The advanced features provided by MOPs make it even more difficult to provide this default value. In addition, in CL, which is a garbage collection language, copying objects really is not required very often, for example. when they are passed as parameters or returned. Thus, implementing your copy operations as needed is likely to be the cleanest solution.

As the saying goes, here is what I found in one of my snippet files that can do what you want:

(defun shallow-copy-object (original) (let* ((class (class-of original)) (copy (allocate-instance class))) (dolist (slot (mapcar #'slot-definition-name (class-slots class))) (when (slot-boundp original slot) (setf (slot-value copy slot) (slot-value original slot)))) copy)) 

You will need MOP support for class-slots and slot-definition-name .

(I probably took this from the old cll thread , but I donโ€™t remember. I never needed something like this, so itโ€™s completely untested.)

You can use it like this (verified using CCL):

 CL-USER> (defclass foo () ((x :accessor x :initarg :x) (y :accessor y :initarg :y))) #<STANDARD-CLASS FOO> CL-USER> (defmethod print-object ((obj foo) stream) (print-unreadable-object (obj stream :identity t :type t) (format stream ":x ~a :y ~a" (x obj) (y obj)))) #<STANDARD-METHOD PRINT-OBJECT (FOO T)> CL-USER> (defparameter *f* (make-instance 'foo :x 1 :y 2)) *F* CL-USER> *f* #<FOO :x 1 :y 2 #xC7E5156> CL-USER> (shallow-copy-object *f*) #<FOO :x 1 :y 2 #xC850306> 
+10
source

Here's a slightly different version of the feature provided by danlei. I wrote this a while ago and just stumbled upon this post. For reasons I donโ€™t fully remember, this calls REINITIALIZE-INSTANCE after copying. I think you could make some changes to the new object by passing extra initargs for this function

eg.

 (copy-instance *my-account* :balance 100.23) 

It is also defined as a general function over objects that are standard objects. What may or may not be right.

 (defgeneric copy-instance (object &rest initargs &key &allow-other-keys) (:documentation "Makes and returns a shallow copy of OBJECT. An uninitialized object of the same class as OBJECT is allocated by calling ALLOCATE-INSTANCE. For all slots returned by CLASS-SLOTS, the returned object has the same slot values and slot-unbound status as OBJECT. REINITIALIZE-INSTANCE is called to update the copy with INITARGS.") (:method ((object standard-object) &rest initargs &key &allow-other-keys) (let* ((class (class-of object)) (copy (allocate-instance class))) (dolist (slot-name (mapcar #'sb-mop:slot-definition-name (sb-mop:class-slots class))) (when (slot-boundp object slot-name) (setf (slot-value copy slot-name) (slot-value object slot-name)))) (apply #'reinitialize-instance copy initargs)))) 
+4
source

Source: https://habr.com/ru/post/918262/


All Articles