% -*- Mode: TeX -*- %%2.5 objects The \term{generic function} \funref{make-instance} creates and returns a new \term{instance} of a \term{class}. The first argument is a \term{class} or the \term{name} of a \term{class}, and the remaining arguments form an \newterm{initialization argument list}. The initialization of a new \term{instance} consists of several distinct steps, including the following: combining the explicitly supplied initialization arguments with default values for the unsupplied initialization arguments, checking the validity of the initialization arguments, allocating storage for the \term{instance}, filling \term{slots} with values, and executing user-supplied \term{methods} that perform additional initialization. Each step of \funref{make-instance} is implemented by a \term{generic function} to provide a mechanism for customizing that step. In addition, \funref{make-instance} is itself a \term{generic function} and thus also can be customized. The \OS\ specifies system-supplied primary \term{methods} for each step and thus specifies a well-defined standard behavior for the entire initialization process. The standard behavior provides four simple mechanisms for controlling initialization: \beginlist \itemitem{\bull} Declaring a \term{symbol} to be an initialization argument for a \term{slot}. An initialization argument is declared by using the \kwd{initarg} slot option to \macref{defclass}. This provides a mechanism for supplying a value for a \term{slot} in a call to \funref{make-instance}. \itemitem{\bull} Supplying a default value form for an initialization argument. Default value forms for initialization arguments are defined by using the \kwd{default-initargs} class option to \macref{defclass}. If an initialization argument is not explicitly provided as an argument to \funref{make-instance}, the default value form is evaluated in the lexical environment of the \macref{defclass} form that defined it, and the resulting value is used as the value of the initialization argument. \itemitem{\bull} Supplying a default initial value form for a \term{slot}. A default initial value form for a \term{slot} is defined by using the \kwd{initform} slot option to \macref{defclass}. If no initialization argument associated with that \term{slot} is given as an argument to \funref{make-instance} or is defaulted by \kwd{default-initargs}, this default initial value form is evaluated in the lexical environment of the \macref{defclass} form that defined it, and the resulting value is stored in the \term{slot}. The \kwd{initform} form for a \term{local slot} may be used when creating an \term{instance}, when updating an \term{instance} to conform to a redefined \term{class}, or when updating an \term{instance} to conform to the definition of a different \term{class}. The \kwd{initform} form for a \term{shared slot} may be used when defining or re-defining the \term{class}. \itemitem{\bull} Defining \term{methods} for \funref{initialize-instance} and \funref{shared-initialize}. The slot-filling behavior described above is implemented by a system-supplied primary \term{method} for \funref{initialize-instance} which invokes \funref{shared-initialize}. The \term{generic function} \funref{shared-initialize} implements the parts of initialization shared by these four situations: when making an \term{instance}, when re-initializing an \term{instance}, when updating an \term{instance} to conform to a redefined \term{class}, and when updating an \term{instance} to conform to the definition of a different \term{class}. The system-supplied primary \term{method} for \funref{shared-initialize} directly implements the slot-filling behavior described above, and \funref{initialize-instance} simply invokes \funref{shared-initialize}. \endlist \beginsubsection{Initialization Arguments} An initialization argument controls \term{object} creation and initialization. It is often convenient to use keyword \term{symbols} to name initialization arguments, but the \term{name} of an initialization argument can be any \term{symbol}, including \nil. An initialization argument can be used in two ways: to fill a \term{slot} with a value or to provide an argument for an initialization \term{method}. A single initialization argument can be used for both purposes. \issue{PLIST-DUPLICATES:ALLOW} An \term{initialization argument list} is a %list of alternating of \term{property list} of initialization argument names and values. Its structure is identical to a \term{property list} and also to the portion of an argument list processed for \keyref{key} parameters. As in those lists, if an initialization argument name appears more than once in an initialization argument list, the leftmost occurrence supplies the value and the remaining occurrences are ignored. The arguments to \funref{make-instance} (after the first argument) form an \term{initialization argument list}. \issue{INITIALIZATION-FUNCTION-KEYWORD-CHECKING} % Error-checking % of initialization argument names is disabled if the keyword argument % pair whose keyword is \kwd{allow-other-keys} and whose value is % \term{non-nil} appears in the \term{initialization argument list}. \endissue{INITIALIZATION-FUNCTION-KEYWORD-CHECKING} \endissue{PLIST-DUPLICATES:ALLOW} An initialization argument can be associated with a \term{slot}. If the initialization argument has a value in the \term{initialization argument list}, the value is stored into the \term{slot} of the newly created \term{object}, overriding any \kwd{initform} form associated with the \term{slot}. A single initialization argument can initialize more than one \term{slot}. An initialization argument that initializes a \term{shared slot} stores its value into the \term{shared slot}, replacing any previous value. An initialization argument can be associated with a \term{method}. When an \term{object} is created and a particular initialization argument is supplied, the \term{generic functions} \funref{initialize-instance}, \funref{shared-initialize}, and \funref{allocate-instance} are called with that initialization argument's name and value as a keyword argument pair. If a value for the initialization argument is not supplied in the \term{initialization argument list}, the \term{method}'s \term{lambda list} supplies a default value. Initialization arguments are used in four situations: when making an \term{instance}, when re-initializing an \term{instance}, when updating an \term{instance} to conform to a redefined \term{class}, and when updating an \term{instance} to conform to the definition of a different \term{class}. Because initialization arguments are used to control the creation and initialization of an \term{instance} of some particular \term{class}, we say that an initialization argument is ``an initialization argument for'' that \term{class}. \endsubsection%{Initialization Arguments} \beginsubsection{Declaring the Validity of Initialization Arguments} \DefineSection{DeclaringInitargValidity} Initialization arguments are checked for validity in each of the four situations that use them. An initialization argument may be valid in one situation and not another. For example, the system-supplied primary \term{method} for \funref{make-instance} defined for \theclass{standard-class} checks the validity of its initialization arguments and signals an error if an initialization argument is supplied that is not declared as valid in that situation. There are two means for declaring initialization arguments valid. \beginlist \itemitem{\bull} Initialization arguments that fill \term{slots} are declared as valid by the \kwd{initarg} slot option to \macref{defclass}. The \kwd{initarg} slot option is inherited from \term{superclasses}. Thus the set of valid initialization arguments that fill \term{slots} for a \term{class} is the union of the initialization arguments that fill \term{slots} declared as valid by that \term{class} and its \term{superclasses}. Initialization arguments that fill \term{slots} are valid in all four contexts. \itemitem{\bull} Initialization arguments that supply arguments to \term{methods} are declared as valid by defining those \term{methods}. The keyword name of each keyword parameter specified in the \term{method}'s \term{lambda list} becomes an initialization argument for all \term{classes} for which the \term{method} is applicable. \issue{INITIALIZATION-FUNCTION-KEYWORD-CHECKING} The presence of {\allowotherkeys} in the \term{lambda list} of an applicable method disables validity checking of initialization arguments. \endissue{INITIALIZATION-FUNCTION-KEYWORD-CHECKING} Thus \term{method} inheritance controls the set of valid initialization arguments that supply arguments to \term{methods}. The \term{generic functions} for which \term{method} definitions serve to declare initialization arguments valid are as follows: \beginlist \itemitem{--} Making an \term{instance} of a \term{class}: \funref{allocate-instance}, \funref{initialize-instance}, and \funref{shared-initialize}. Initialization arguments declared as valid by these \term{methods} are valid when making an \term{instance} of a \term{class}. \itemitem{--} Re-initializing an \term{instance}: \funref{reinitialize-instance} and \funref{shared-initialize}. Initialization arguments declared as valid by these \term{methods} are valid when re-initializing an \term{instance}. \itemitem{--} Updating an \term{instance} to conform to a redefined \term{class}: \funref{update-instance-for-redefined-class} and \funref{shared-initialize}. Initialization arguments declared as valid by these \term{methods} are valid when updating an \term{instance} to conform to a redefined \term{class}. \itemitem{--} Updating an \term{instance} to conform to the definition of a different \term{class}: \funref{update-instance-for-different-class} and \funref{shared-initialize}. Initialization arguments declared as valid by these \term{methods} are valid when updating an \term{instance} to conform to the definition of a different \term{class}. \endlist \endlist The set of valid initialization arguments for a \term{class} is the set of valid initialization arguments that either fill \term{slots} or supply arguments to \term{methods}, along with the predefined initialization argument \kwd{allow-other-keys}. The default value for \kwd{allow-other-keys} is \nil. \issue{INITIALIZATION-FUNCTION-KEYWORD-CHECKING} % The meaning of % \kwd{allow-other-keys} is the same as when it is passed to an ordinary % \term{function}. Validity checking of initialization arguments is disabled if the value of the initialization argument \kwd{allow-other-keys} is \term{true}. \endissue{INITIALIZATION-FUNCTION-KEYWORD-CHECKING} \endsubsection%{Declaring the Validity of Initialization Arguments} \beginsubsection{Defaulting of Initialization Arguments} A default value \term{form} can be supplied for an initialization argument by using the \kwd{default-initargs} \term{class} option. If an initialization argument is declared valid by some particular \term{class}, its default value form might be specified by a different \term{class}. In this case \kwd{default-initargs} is used to supply a default value for an inherited initialization argument. The \kwd{default-initargs} option is used only to provide default values for initialization arguments; it does not declare a \term{symbol} as a valid initialization argument name. Furthermore, the \kwd{default-initargs} option is used only to provide default values for initialization arguments when making an \term{instance}. The argument to the \kwd{default-initargs} class option is a list of alternating initialization argument names and \term{forms}. Each \term{form} is the default value form for the corresponding initialization argument. The default value \term{form} of an initialization argument is used and evaluated only if that initialization argument does not appear in the arguments to \funref{make-instance} and is not defaulted by a more specific \term{class}. The default value \term{form} is evaluated in the lexical environment of the \macref{defclass} form that supplied it; the resulting value is used as the initialization argument's value. The initialization arguments supplied to \funref{make-instance} are combined with defaulted initialization arguments to produce a \term{defaulted initialization argument list}. A \term{defaulted initialization argument list} is a list of alternating initialization argument names and values in which unsupplied initialization arguments are defaulted and in which the explicitly supplied initialization arguments appear earlier in the list than the defaulted initialization arguments. Defaulted initialization arguments are ordered according to the order in the \term{class precedence list} of the \term{classes} that supplied the default values. There is a distinction between the purposes of the \kwd{default-initargs} and the \kwd{initform} options with respect to the initialization of \term{slots}. The \kwd{default-initargs} class option provides a mechanism for the user to give a default value \term{form} for an initialization argument without knowing whether the initialization argument initializes a \term{slot} or is passed to a \term{method}. If that initialization argument is not explicitly supplied in a call to \funref{make-instance}, the default value \term{form} is used, just as if it had been supplied in the call. In contrast, the \kwd{initform} slot option provides a mechanism for the user to give a default initial value form for a \term{slot}. An \kwd{initform} form is used to initialize a \term{slot} only if no initialization argument associated with that \term{slot} is given as an argument to \funref{make-instance} or is defaulted by \kwd{default-initargs}. \idxtext{order of evaluation}\idxtext{evaluation order} The order of evaluation of default value \term{forms} for initialization arguments and the order of evaluation of \kwd{initform} forms are undefined. If the order of evaluation is important, \funref{initialize-instance} or \funref{shared-initialize} \term{methods} should be used instead. \endsubsection%{Defaulting of Initialization Arguments} \beginsubsection{Rules for Initialization Arguments} \DefineSection{InitargRules} The \kwd{initarg} slot option may be specified more than once for a given \term{slot}. The following rules specify when initialization arguments may be multiply defined: \beginlist \itemitem{\bull} A given initialization argument can be used to initialize more than one \term{slot} if the same initialization argument name appears in more than one \kwd{initarg} slot option. \itemitem{\bull} A given initialization argument name can appear in the \term{lambda list} of more than one initialization \term{method}. \itemitem{\bull} A given initialization argument name can appear both in an \kwd{initarg} slot option and in the \term{lambda list} of an initialization \term{method}. \endlist \reviewer{The next three paragraphs could be replaced by ``If two or more initialization arguments that initialize the same slot appear in the \term{defaulted initialization argument list}, the leftmost of these supplies the value, even if they have different names.'' And the rest would follow from the rules above.} If two or more initialization arguments that initialize the same \term{slot} are given in the arguments to \funref{make-instance}, the leftmost of these initialization arguments in the \term{initialization argument list} supplies the value, even if the initialization arguments have different names. If two or more different initialization arguments that initialize the same \term{slot} have default values and none is given explicitly in the arguments to \funref{make-instance}, the initialization argument that appears in a \kwd{default-initargs} class option in the most specific of the \term{classes} supplies the value. If a single \kwd{default-initargs} class option specifies two or more initialization arguments that initialize the same \term{slot} and none is given explicitly in the arguments to \funref{make-instance}, the leftmost in the \kwd{default-initargs} class option supplies the value, and the values of the remaining default value \term{forms} are ignored. Initialization arguments given explicitly in the arguments to \funref{make-instance} appear to the left of defaulted initialization arguments. Suppose that the classes $C\sub 1$ and $C\sub 2$ supply the values of defaulted initialization arguments for different \term{slots}, and suppose that $C\sub 1$ is more specific than $C\sub 2$; then the defaulted initialization argument whose value is supplied by $C\sub 1$ is to the left of the defaulted initialization argument whose value is supplied by $C\sub 2$ in the \term{defaulted initialization argument list}. If a single \kwd{default-initargs} class option supplies the values of initialization arguments for two different \term{slots}, the initialization argument whose value is specified farther to the left in the \kwd{default-initargs} class option appears farther to the left in the \term{defaulted initialization argument list}. \reviewer{Barmar: End of claim made three paragraphs back.} If a \term{slot} has both an \kwd{initform} form and an \kwd{initarg} slot option, and the initialization argument is defaulted using \kwd{default-initargs} or is supplied to \funref{make-instance}, the captured \kwd{initform} form is neither used nor evaluated. The following is an example of the above rules: \code (defclass q () ((x :initarg a))) (defclass r (q) ((x :initarg b)) (:default-initargs a 1 b 2)) \endcode $$\vbox{\halign{\strut#\hfil&\quad\hfil#\hfil&\quad\hfil#\hfil\cr {}&\bf Defaulted&{}\cr \bf Form&\bf Initialization Argument List&\bf Contents of Slot X\cr \noalign{\hrule} {\tt (make-instance 'r)}&{\tt (a 1 b 2)}&{\tt 1}\cr {\tt (make-instance 'r 'a 3)}&{\tt (a 3 b 2)}&{\tt 3}\cr {\tt (make-instance 'r 'b 4)}&{\tt (b 4 a 1)}&{\tt 4}\cr {\tt (make-instance 'r 'a 1 'a 2)}&{\tt (a 1 a 2 b 2)}&{\tt 1}\cr}}$$ \endsubsection%{Rules for Initialization arguments} \beginsubsection{Shared-Initialize} \DefineSection{SharedInitialize} The \term{generic function} \funref{shared-initialize} is used to fill the \term{slots} of an \term{instance} using initialization arguments and \kwd{initform} forms when an \term{instance} is created, when an \term{instance} is re-initialized, when an \term{instance} is updated to conform to a redefined \term{class}, and when an \term{instance} is updated to conform to a different \term{class}. It uses standard \term{method} combination. It takes the following arguments: the \term{instance} to be initialized, a specification of a set of \term{names} of \term{slots} \term{accessible} in that \term{instance}, and any number of initialization arguments. The arguments after the first two must form an \term{initialization argument list}. The second argument to \funref{shared-initialize} may be one of the following: \beginlist \itemitem{\bull} It can be a (possibly empty) \term{list} of \term{slot} names, which specifies the set of those \term{slot} names. % \reviewer{Barmar: This next bullet item is redundant with the previous, % since NIL -is- a LIST. If there was some confusion, we could say ``(possibly empty)'' % in the previous item.} % % \itemitem{\bull} It can be \nil, which specifies the empty set of % \term{slot} names. \itemitem{\bull} It can be the symbol \t, which specifies the set of all of the \term{slots}. \endlist There is a system-supplied primary \term{method} for \funref{shared-initialize} whose first \term{parameter specializer} is \theclass{standard-object}. This \term{method} behaves as follows on each \term{slot}, whether shared or local: \beginlist \itemitem{\bull} If an initialization argument in the \term{initialization argument list} specifies a value for that \term{slot}, that value is stored into the \term{slot}, even if a value has already been stored in the \term{slot} before the \term{method} is run. The affected \term{slots} are independent of which \term{slots} are indicated by the second argument to \funref{shared-initialize}. \itemitem{\bull} Any \term{slots} indicated by the second argument that are still unbound at this point are initialized according to their \kwd{initform} forms. For any such \term{slot} that has an \kwd{initform} form, that \term{form} is evaluated in the lexical environment of its defining \macref{defclass} form and the result is stored into the \term{slot}. For example, if a \term{before method} stores a value in the \term{slot}, the \kwd{initform} form will not be used to supply a value for the \term{slot}. If the second argument specifies a \term{name} that does not correspond to any \term{slots} \term{accessible} in the \term{instance}, the results are unspecified. \itemitem{\bull} The rules mentioned in {\secref\InitargRules} are obeyed. \endlist The generic function \funref{shared-initialize} is called by the system-supplied primary \term{methods} for \funref{reinitialize-instance}, \funref{update-instance-for-different-class}, \funref{update-instance-for-redefined-class}, and \funref{initialize-instance}. Thus, \term{methods} can be written for \funref{shared-initialize} to specify actions that should be taken in all of these contexts. \endsubsection%{Shared-Initialize} \beginsubsection{Initialize-Instance} The \term{generic function} \funref{initialize-instance} is called by \funref{make-instance} to initialize a newly created \term{instance}. It uses \term{standard method combination}. \term{Methods} for \funref{initialize-instance} can be defined in order to perform any initialization that cannot be achieved %%This was the only case of a half-glossary-term in the entire spec. -kmp 1-Jan-91 %with the simple \term{slot}-filling mechanisms. simply by supplying initial values for \term{slots}. During initialization, \funref{initialize-instance} is invoked after the following actions have been taken: \beginlist \itemitem{\bull} The \term{defaulted initialization argument list} has been computed by combining the supplied \term{initialization argument list} with any default initialization arguments for the \term{class}. \itemitem{\bull} The validity of the \term{defaulted initialization argument list} has been checked. If any of the initialization arguments has not been declared as valid, an error is signaled. \itemitem{\bull} A new \term{instance} whose \term{slots} are unbound has been created. \endlist The generic function \funref{initialize-instance} is called with the new \term{instance} and the defaulted initialization arguments. There is a system-supplied primary \term{method} for \funref{initialize-instance} whose \term{parameter specializer} is \theclass{standard-object}. This \term{method} calls the generic function \funref{shared-initialize} to fill in the \term{slots} according to the initialization arguments and the \kwd{initform} forms for the \term{slots}; the generic function \funref{shared-initialize} is called with the following arguments: the \term{instance}, \t, and the defaulted initialization arguments. Note that \funref{initialize-instance} provides the \term{defaulted initialization argument list} in its call to \funref{shared-initialize}, so the first step performed by the system-supplied primary \term{method} for \funref{shared-initialize} takes into account both the initialization arguments provided in the call to \funref{make-instance} and the \term{defaulted initialization argument list}. \term{Methods} for \funref{initialize-instance} can be defined to specify actions to be taken when an \term{instance} is initialized. If only \term{after methods} for \funref{initialize-instance} are defined, they will be run after the system-supplied primary \term{method} for initialization and therefore will not interfere with the default behavior of \funref{initialize-instance}. The \OS\ provides two \term{functions} that are useful in the bodies of \funref{initialize-instance} methods. \Thefunction{slot-boundp} returns a \term{generic boolean} value that indicates whether a specified \term{slot} has a value; this provides a mechanism for writing \term{after methods} for \funref{initialize-instance} that initialize \term{slots} only if they have not already been initialized. \Thefunction{slot-makunbound} causes the \term{slot} to have no value. \endsubsection%{INITIALIZE-INSTANCE} \beginsubsection{Definitions of Make-Instance and Initialize-Instance} The generic function \funref{make-instance} behaves as if it were defined as follows, except that certain optimizations are permitted: \code (defmethod make-instance ((class standard-class) &rest initargs) ... (let ((instance (apply #'allocate-instance class initargs))) (apply #'initialize-instance instance initargs) instance)) (defmethod make-instance ((class-name symbol) &rest initargs) (apply #'make-instance (find-class class-name) initargs)) \endcode %This is the code: %(defmethod make-instance ((class standard-class) &rest initargs) % (setq initargs (default-initargs class initargs)) % (let* ((proto (class-prototype class)) % (methods % (append % (compute-applicable-methods #'allocate-instance `(,class)) % (compute-applicable-methods #'initialize-instance `(,proto)) % (compute-applicable-methods #'shared-initialize `(,proto nil))))) % (unless % (subsetp % (let ((keys '())) % (do ((plist initargs (cddr plist))) % ((null plist) keys) % (push (car plist) keys))) % (union % (class-slot-initargs class) % (reduce #'union (mapcar #'function-keywords methods)))) % (error ...))) % (let ((instance (apply #'allocate-instance class initargs))) % (apply #'initialize-instance instance initargs) % instance)) The elided code in the definition of \funref{make-instance} %% Per X3J13. -kmp 05-Oct-93 augments the \f{initargs} with any \term{defaulted initialization arguments} and checks the %% Per X3J13. -kmp 05-Oct-93 %supplied resulting initialization arguments to determine whether an initialization argument was supplied that neither filled a \term{slot} nor supplied an argument to an applicable \term{method}. %This check could be implemented using the generic functions % ???\funref{class-prototype},??? \funref{compute-applicable-methods}, %\funref{function-keywords}, and ???\funref{class-slot-initargs}. ??? %See Chapter~3 for a %description of this initialization argument check. The generic function \funref{initialize-instance} behaves as if it were defined as follows, except that certain optimizations are permitted: \code (defmethod initialize-instance ((instance standard-object) &rest initargs) (apply #'shared-initialize instance t initargs))) \endcode % Barmar complains that "Programmer Interface level" is not defined. % Presumably it means "this specification". % Ditto "the meta-object level" is not defined. % Presumably it should just be omitted as beyond the scope of this standard, % or else we should define the term somewhere (e.g., the glossary). % I decided to just trim it down to where glossary words weren't needed. -kmp 6-Jan-91 These procedures can be customized. % at either the Programmer Interface level, % the meta-object level, or both. Customizing at the Programmer Interface level includes using the \kwd{initform}, \kwd{initarg}, and \kwd{default-initargs} options to \macref{defclass}, as well as defining \term{methods} for \funref{make-instance}, %% Per X3J13. -kmp 05-Oct-93 \funref{allocate-instance}, and \funref{initialize-instance}. It is also possible to define \term{methods} for \funref{shared-initialize}, which would be invoked by the generic functions \funref{reinitialize-instance}, \funref{update-instance-for-redefined-class}, \funref{update-instance-for-different-class}, and \funref{initialize-instance}. The meta-object level supports additional customization. %by allowing methods to be defined on \funref{make-instance}, %???\b{default-initargs}???, and \funref{allocate-instance}. %Chapters~2 and~3 document each of these generic %functions and the system-supplied primary methods. Implementations are permitted to make certain optimizations to \funref{initialize-instance} and \funref{shared-initialize}. The description of \funref{shared-initialize} in Chapter~7 mentions the possible optimizations. %Because of optimization, the check for valid initialization arguments %might not be implemented using the generic functions %???\funref{class-prototype},??? %\funref{compute-applicable-methods}, \funref{function-keywords}, and %???\funref{class-slot-initargs}???. In addition, %methods for the generic function %???\funref{default-initargs},??? and the %system-supplied primary methods for %???\funref{allocate-instance}???, %\funref{initialize-instance}, and \funref{shared-initialize} might not be called on %every call to \funref{make-instance} or might not receive exactly the %arguments that would be expected. \endsubsection%{Definitions of MAKE-INSTANCE and Initialize-Instance}