Skip to main content

initialize-instance

initialize-instance Standard Generic Function

Syntax:

initialize-instance instance &rest initargs &key &allow-other-keys ! instance

Method Signatures:

initialize-instance (instance standard-object) &rest initargs

Arguments and Values:

instance—an object.

initargs—a defaulted initialization argument list.

Description:

Called by make-instance to initialize a newly created instance. The generic function is called with the new instance and the defaulted initialization argument list.

The system-supplied primary method on initialize-instance initializes the slots of the instance with values according to the initargs and the :initform forms of the slots. It does this by calling the generic function shared-initialize with the following arguments: the instance, t (this indicates that all slots for which no initialization arguments are provided should be initialized according to their :initform forms), and the initargs.

Programmers can define methods for initialize-instance to specify actions to be taken when an instance is initialized. If only after methods are defined, they will be run after the system-supplied primary method for initialization and therefore will not interfere with the default behavior of initialize-instance.

See Also:

shared-initialize, make-instance, slot-boundp, slot-makunbound, Section 7.1 (Object Creation and Initialization), Section 7.1.4 (Rules for Initialization Arguments), Section 7.1.2 (Declaring the Validity of Initialization Arguments)

Expanded Reference: initialize-instance

Basic Customization with :after Methods

initialize-instance is called by make-instance to set up a newly created instance. The recommended way to customize initialization is to define :after methods, which run after the system-supplied primary method has filled in slot values from initargs and initforms.

(defclass person ()
((first-name :initarg :first-name :accessor first-name)
(last-name :initarg :last-name :accessor last-name)
(full-name :accessor full-name)))

(defmethod initialize-instance :after ((p person) &key)
(setf (full-name p)
(format nil "~A ~A" (first-name p) (last-name p))))

(let ((p (make-instance 'person :first-name "Jane" :last-name "Doe")))
(full-name p))
=> "Jane Doe"

Validation During Initialization

An :after method can signal an error if required slots are missing or invalid.

(defclass positive-pair ()
((x :initarg :x :accessor pair-x)
(y :initarg :y :accessor pair-y)))

(defmethod initialize-instance :after ((pp positive-pair) &key)
(unless (and (slot-boundp pp 'x) (slot-boundp pp 'y))
(error "Both X and Y must be provided"))
(unless (and (plusp (pair-x pp)) (plusp (pair-y pp)))
(error "X and Y must be positive numbers")))

(let ((pp (make-instance 'positive-pair :x 3 :y 5)))
(list (pair-x pp) (pair-y pp)))
=> (3 5)

;; This would signal an error:
;; (make-instance 'positive-pair :x -1 :y 5)
;; Error: X and Y must be positive numbers

Accessing Initargs in :after Methods

Custom initargs can be accepted via &key and used for initialization logic that goes beyond simple slot filling.

(defclass circle ()
((radius :initarg :radius :accessor circle-radius)
(diameter :accessor circle-diameter)
(perimeter :accessor circle-perimeter)))

(defmethod initialize-instance :after ((c circle) &key)
(let ((r (circle-radius c)))
(setf (circle-diameter c) (* 2 r))
(setf (circle-perimeter c) (* 2 pi r))))

(let ((c (make-instance 'circle :radius 5)))
(list (circle-radius c)
(circle-diameter c)
(floor (circle-perimeter c))))
=> (5 10 31)

Conditional Slot Initialization

Use slot-boundp inside an :after method to initialize only those slots that have not been set by initargs.

(defclass entry ()
((key :initarg :key :accessor entry-key)
(label :initarg :label :accessor entry-label)))

(defmethod initialize-instance :after ((e entry) &key)
(unless (slot-boundp e 'label)
(setf (entry-label e)
(string-capitalize (string (entry-key e))))))

(entry-label (make-instance 'entry :key :hello))
=> "Hello"

(entry-label (make-instance 'entry :key :hello :label "Custom"))
=> "Custom"

Inheritance of :after Methods

When classes form an inheritance chain, :after methods from all classes in the chain run in most-specific-last order (after the primary method). This allows each class to contribute its own initialization.

(defclass base-widget ()
((id :accessor widget-id)))

(defmethod initialize-instance :after ((w base-widget) &key)
(setf (widget-id w) (gensym "WIDGET-")))

(defclass labeled-widget (base-widget)
((label :initarg :label :accessor widget-label)
(display-label :accessor display-label)))

(defmethod initialize-instance :after ((w labeled-widget) &key)
(setf (display-label w)
(format nil "[~A] ~A" (widget-id w) (widget-label w))))

(let ((w (make-instance 'labeled-widget :label "OK")))
;; Both :after methods ran: base-widget's first, then labeled-widget's
(values (symbolp (widget-id w))
(stringp (display-label w))))
=> T
=> T