slot-unbound
slot-unbound Standard Generic Function
Syntax:
slot-unbound class instance slot-name → {result}*
Method Signatures:
slot-unbound (class t) instance slot-name
Arguments and Values:
class—the class of the instance.
instance—the instance in which an attempt was made to read the unbound slot.
slot-name—the name of the unbound slot.
result—an object.
Description:
The generic function slot-unbound is called when an unbound slot is read in an instance whose metaclass is standard-class. The default method signals an error of type unbound-slot. The name slot of the unbound-slot condition is initialized to the name of the offending variable, and the instance slot of the unbound-slot condition is initialized to the offending instance.
The generic function slot-unbound is not intended to be called by programmers. Programmers may write methods for it. The function slot-unbound is called only indirectly by slot-value.
If slot-unbound returns, only the primary value will be used by the caller, and all other values will be ignored.
Exceptional Situations:
The default method on slot-unbound signals an error of type unbound-slot.
See Also:
slot-makunboundNotes:
An unbound slot may occur if no :initform form was specified for the slot and the slot value has not been set, or if slot-makunbound has been called on the slot.
Expanded Reference: slot-unbound
Default Behavior
slot-unbound is called by slot-value when an unbound slot is read. The default method signals an unbound-slot error.
(defclass item ()
((value :initarg :value)))
(let ((obj (make-instance 'item)))
(handler-case (slot-value obj 'value)
(unbound-slot (c)
(format nil "Unbound: ~A" (cell-error-name c)))))
=> "Unbound: VALUE"
Providing a Default Value for Unbound Slots
You can define a method on slot-unbound to return a default value instead of signaling an error. This implements lazy initialization.
(defclass lazy-default ()
((data :initarg :data :accessor lazy-data)))
(defmethod slot-unbound ((class t) (instance lazy-default) slot-name)
(if (eq slot-name 'data)
(setf (lazy-data instance) (list :default))
(call-next-method)))
(let ((obj (make-instance 'lazy-default)))
;; First access triggers slot-unbound, which initializes the slot
(lazy-data obj))
=> (:DEFAULT)
Lazy Initialization Pattern
slot-unbound is particularly useful for expensive computations that should only happen on first access.
(defclass expensive-resource ()
((connection :accessor resource-connection)))
(defmethod slot-unbound ((class t) (obj expensive-resource)
(slot-name (eql 'connection)))
;; Simulate creating an expensive resource on first access
(setf (resource-connection obj) (cons :connection (get-universal-time))))
(let ((r (make-instance 'expensive-resource)))
(consp (resource-connection r)))
=> T