Continuing our series of posts on the more obscure commands of Lisp that beginners arriving from C++ might not have encountered and might not know when to use, we come to allocate-instance.
Think of this command as something that returns an object that hasn’t been constructed/initialized. It’s an operation that has no counterpart in C++. The object is built without filling in any of its slots.
Now, this may seem like a somewhat unnecessary function. After all, why not just build the object with its slots initialized, and then overwrite the slots in a separate operation? Well, there can be cases where allowing the object to be built normally, with make-instance, is undesirable. A simple example might be the following:
;; A situation where you might prefer allocate-instance to ;; make-instance. (let ((number-seq 0)) (defun get-next-seq-id () (incf number-seq))) (defclass myclass () ((id :reader get-id :initform (get-next-seq-id)) (data :accessor get-data))) (defun demonstrate () (let ((obj1 (make-instance 'myclass)) (obj2 (make-instance 'myclass)) (obj3 (make-instance 'myclass))) (format t "ID of obj1= ~D~%" (get-id obj1)) (format t "ID of obj2= ~D~%" (get-id obj2)) (format t "ID of obj3= ~D~%" (get-id obj3))))
So, let’s say you’ve built this system, and you have some need to construct a new object which reuses an earlier ID. Perhaps there was a bug that showed up only when a specific ID was passed into your hashing function, and you need to replicate the bug, but the object no longer exists. As set up, a call to make-instance results in the next number in the sequence being allocated, and there’s no way to prevent the ID allocator from incrementing its internal state.
By using allocate-instance, you create a new object without calling its initform slot options. Of course, you can imagine other contexts where avoiding the initform options are desirable, such as if the initform is very time-consuming, or if it invokes operations that affect the state in some way, such as opening network connections or disc files.
One place where I have seen allocate-instance used is in a generic object serializer in the cl-containers package. There, objects can be passed to a method that writes them out to disc, and later they can be read back in. To avoid complications during the read-in, the objects are allocated with allocate-instance and then the slots are individually restored from the disc file using a (setf (slot-value …) …) construct.