Previous section: Slot Options

Dylan reference manual -- Instance creation

Instance creation

The creation and initialization of instances is controlled by the generic functions initialize and make.

Overview

Instance 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 Inheritance

If 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.

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.

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.

Initialization of Class Allocated Slots

Initialization 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:

Testing the Initialization of a Slot

A 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.

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.

Next section: Reflective Operations on Types