Instance creationThe creation and initialization of instances is controlled by the generic functions initialize and make.
OverviewInstance creation and initialization works in the following way:
Definitions of make and initialize
make class #key #all-keys => instance [Generic Function]
make returns an instance of class, with characteristics specified by the keyword value pairs.
Dylan does not specify whether the value returned must be a newly allocated instance, or whether make is permitted to return a previously created instance. If a new instance is allocated, make will call initialize on the instance before returning it.
The object returned is guaranteed to be a general instance of class but not necessarily a direct instance of class. This liberality allows make to be called on an abstract class; it can instantiate and return a direct instance of one of the concrete subclasses of the abstract class.
(Note that the default method on make returns a newly allocated direct instance of class .)
Programmers may customize make for particular classes by defining methods specialized by singleton specializers. These methods may obtain the default make behavior, if desired, by calling next-method.
In the absence of any customization, the default make method is invoked.
make class #rest supplied-initialization-arguments #key => instance [Method]
The default method for make does the following:
It signals an error if class is abstract. An instantiable abstract class must override this method with its own method for make.
Any deferred evaluations which have not yet been performed for class and its superclasses are performed first.
If supplied-initialization-arguments contains duplicate keywords, make will use the leftmost occurence. (This is consistent with #key argument conventions in function calls.)
make starts with supplied-initialization-arguments and constructs the set of defaulted initialization arguments , which will be used in creating and initializing the instance, by augmenting it with any additional initialization arguments for which default values are defined by class or any of its superclasses. make signals an error if any required initialization argument is absent from the defaulted initialization arguments, or if any of the defaulted initialization arguments are not valid for initialization of that class (that is, some keyword is neither usable for slot initialization nor recognized by some initialize method applicable to an instance of class ). Note that init-functions used to construct the defaulted initialization arguments will only be invoked if the initialization argument is in fact missing from the supplied initialization arguments.
make then allocates an instance and initializes all slots for which it can compute values. If a slot is keyword initializable and the corresponding initialization argument is present in the defaulted initialization arguments , the slot is set to that value. Otherwise, if the slot has a default initial value specification, that is used to provide the initial value: either the init-value, or the result of calling the init-function. In either case, an error is signaled if the value is not of the type declared for the slot.
The exact order in which instance allocation and init-function invocation occurs in the above is undefined.
make calls initialize on the initialized instance and the defaulted initialization arguments, to perform any custom or complex initializations. User-defined initialize methods may use #key parameters to access particular initialization arguments, or #rest to access the entire set of initialization arguments. If the entire set of initialization arguments is examined and supplied initialization arguments contained duplicate keywords, it is undefined whether any entries other than the leftmost for that keyword will be present.
make ignores any values returned by the call to initialize, and returns the instance.
initialize instance #key #all-keys [Generic Function]
The initialize generic function provides a way for users to handle initialization of instances which cannot be expressed simply by init-values or init-functions. This is typically because a computation requires inputs from initargs or slot values, or a single computation needs to be used to initialize multiple slots.
For instance, the following example shows a <triangle> class which presents an interface of storing three sides, but actually stores two sides and an angle:define class <triangle> (<shape>) slot side-a, required-init-keyword: side-a:; slot side-b, required-init-keyword: side-b:; slot angle-C; virtual slot side-c, required-init-keyword: side-c: end class <triangle>; define method initialize (x :: <triangle>, #key side-a, side-b, side-c) next-method(); x.angle-C := three-sides-to-angle (side-a, side-b, side-c); end method initialize;By convention, all initialize methods should call next-method very early, to make sure that any initializations from less specific classes are performed first. Dylan implementations may provide warnings about code style for methods on initialize which do not call next-method.
The initialize generic function permits all keywords, and requires none. It does this because the keyword argument checking has already been performed by the default method on make.
initialize instance :: <object> #key [Method]
The default initialize method does nothing. It is present so that next-method() may be used with abandon by modularly written initialize methods.
Initialization Argument InheritanceIf a slot is keyword-initializable, it is possible to change the default value for the initialization argument alone, without mention of the slot.
This is illustrated by the modified default for favorite-beverage in the following example.define class <person> (...) slot favorite-beverage, init-value: #"milk", init-keyword: favorite-beverage:; slot name required-init-keyword: name:; end class <person>; define class <astronaut> (<person>) keyword favorite-beverage: init-value: #"tang"; keyword name: init-value: "Bud"; end class <astronaut>;Another common use is to supply a default which is required in the superclass, as illustrated with the name: init-keyword above; this makes the name: keyword no longer required when calling make on <astronaut>.
Initialization argument specification inheritance is defined as follows. There are four cases:
a. The type: argument, which defaults to <object>, specifies the required type of the initialization argument.
- A slot specification which supplies an init-keyword K by using required-init-keyword: is treated as if the initialization argument specification required-init-keyword: K had been specified in the class definition.
- A slot specification which supplies both an init-keyword and also an init-value or init-function is not equivalent to an initialization argument specification which includes the init-keyword and init-value or init-function. The former is used to default the value of the slot directly, but does not affect the defaulted initialization arguments; the latter is used to default the value of the slot indirectly, by affecting the defaulted initialization arguments.
- The initialization argument is being specified for the first time -- it is not inherited from any superclasses.
b. If the initialization argument is specified with required-init-keyword: then it is required, otherwise it is optional.
c. If the initialization argument is specified with init-keyword:, then it can provide an initial value specification which is used by the default make method to provide a default value for the initialization argument in the defaulted initialization arguments. This is either a value specified with init-value: or a function (called each time a value is needed) specified with init-function:
a. The type must be a subtype of the type of the inherited initialization argument.
- An initialization argument specification is being specified for an initialization argument which is inherited from a single superclass.
b. The initialization argument is required if the overriding initialization argument specification uses required-init-keyword:, or if the inherited initialization argument specification is required and the overriding initialization argument specification uses neither init-value: nor init-function:. When the the overriding initialization argument specification uses required-init-keyword:, any init-value or init-function in the inherited initialization argument specification is discarded.
c. Otherwise, the initialization argument is optional. If the overriding specification provides an init-value: or init-function:, then that is used to compute the defaulted initialization argument when the class is instantiated. Otherwise, the inherited initial value specification is used.
(3)b. means that a subclass can force an initialization argument used by a superclass to become required, but cannot force a required initialization argument to become optional without specifying a default value to be used.
- An initialization argument specification is being inherited from multiple superclasses. If the superclasses have exactly the same definition for the initialization argument, then that definition can simply be inherited. If the definitions differ, then the class which combines these other classes must provide an initialization argument specification which is compatible with all of the inherited ones, as described above.
Initialization of Class Allocated SlotsInitialization of slots of allocations class and each-subclass works in the following way. There are four cases to consider, depending on whether the slot is keyword initializable, and whether any way to compute a default value was specified:
- The slot is not keyword initializable, and there is no default value for the slot (i.e., neither init-value: nor init-function: were specified). The slot value is not changed, and if it is presently uninitialized it remains so.
- The slot is not keyword initializable, but there is a default value for it (specified with either init-value: or init-function:). The init-value (or value of the call to the init-function) is used to initialize the slot some time before or during the first call to make on a class that shares this slot.
- The slot is keyword-initializable, but the corresponding initialization argument is absent from the defaulted initialization arguments of the call to make. The slot value is not changed, and if it is presently uninitialized it remains so.
- The slot is keyword-initializable, and the corresponding initialization argument is present in the defaulted initialization arguments of the call to make. The slot is unconditionally set to the value of that initialization argument.
Testing the Initialization of a SlotA program can test to see whether a slot has been initialized.
slot-initialized? instance getter => boolean [Function]
slot-initialized? returns true if the slot in instance that would be accessed by the getter generic function is initialized. If the slot is not initialized, then false is returned.Next section: Reflective Operations on Types
slot-initialized? will signal an error if the getter does not access a slot in the instance.
There is no mechanism for resetting a slot to the uninitialized state.