:initform and :default-initargs

There are two means of automatic initialization of CLOS slot values, :initform and :default-initargs. Chris Riesbeck makes a strong case for preferring :default-initargs.

Here’s a simplified example of the syntactic difference, taken from some Quicklisp code. Consider modeling version control commands with CLOS. Here’s a possible design:

(defclass vc-command ()
  ((command
    :initarg :command
    :accessor command)
   (checkout-subcommand
    :initarg :checkout-subcommand
    :accessor checkout-subcommand)))

To make subclasses for CVS and git, one option is to use the initform slot option:

(defclass vc-git (vc-command)
  ((command
    :initform "git")
   (checkout-subcommand
    :initform "clone")))

(defclass vc-cvs (vc-command)
  ((command
    :initform "cvs")
   (checkout-subcommand
    :initform "co")))

I prefer to use :default-initargs to avoid recapping the slots:

(defclass vc-git (vc-command)
  ()
  (:default-initargs
   :command "git"
   :checkout-subcommand "clone"))

(defclass vc-cvs (vc-command)
  ()
  (:default-initargs
   :command "cvs"
   :checkout-subcommand "co"))

:default-initargs also need not correspond to slots. They can be used to pass extra arguments to initialization functions like initialize-instance:

(defclass fribble (dibble)
  ()
  (:default-initargs
   :persist nil))

(defmethod initialize-instance :after ((instance dibble) &key persist)
  (when persist
    (persist-object instance)))