SETQ or SETF With Defensive Copy

208 Views Asked by At

I am wondering about how one could do something as follows in Common Lisp. Suppose I have an object (entity) in memory that is unique at a certain time. What I would like to do is set some variable to be the state of that object, as snapshot at a certain time. The original entity may then evolve. However, I would like to make sure that the variable still points to the state of that entity in the past.

It appears that what I need is something along of the lines of a deep-copy + a setter. The complicating factor is that, at times, the nature of the entity is unknown. It may be an array or it may be a hashtable. It may likewise be an object.

Any advice is appreciated.

1

There are 1 best solutions below

3
On BEST ANSWER

The only thing you need is immutable objects and only update the bindings. setq (and setf with a symbol as first argument) does this perfectly. Here are some examples:

(defparameter *test* '(1 2))
(defparameter *test2* *test*) ; a copy
(setf *test* (cdr *test*))    ; *test* is (2), but *test2* is still (1 2)
(defparameter *test3* *test*) ; a new copy
(setf *test* (cons 3 *test*)) ; *test* is (3 2), but *test2* is still (1 2) and *test3* is still (2)

push and pop does this for you. Here is the same code:

(defparameter *test* '(1 2))
(defparameter *test2* *test*) ; a copy
(pop *test*)                  ; *test* is (2), but *test2* is still (1 2)
(defparameter *test3* *test*) ; a new copy
(push 3 *test*)               ; (3 2), but *test2* is still (1 2) and *test3* is still (2)

What I do not do here is (setf (car *test*) 3) since that mutates the object and all references will get the same object since they point at the object I changed.

So if you have some sort of state that is more complex, like a hash table, you would need to turn it into a tree so that you can change log(n) nodes per update and it will work in the same manner, that old references still have the same state.