Chapter 5

Types and Classes

Instance Creation and Initialization

The creation and initialization of instances is controlled by the generic functions initialize and make, using initialization information supplied by the class definition and by keyword arguments in the call to make. Much of this behavior is supplied by the default make method defined on <class>.

Overview

Instance creation and initialization proceeds through the following steps:

The values of virtual slots are not automatically initialized when a new instance is created. The programmer must perform any necessary initialization. This would usually be done inside a method on initialize. Because the values of virtual slots are often computed from other values at run-time, many virtual slots will not require any explicit initialization.

Additional Behavior of Make and Initialize

The object returned by make is guaranteed to be a general instance of the first argument to make, but not necessarily a direct instance. 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.

define abstract class <dog> (<object>)
end class
define class <yorkshire-terrier> (<dog>)
end class
define method make (the-class == <dog>, #rest init-args, #key)
  apply(make, <yorkshire-terrier>, init-args)
end

make(<dog>)
 ⇒ {instance of <yorkshire-terrier>}

make is not required to return a newly allocated instance. It may return a previously created instance if that is appropriate. If a new instance is allocated, make will call initialize on the instance before returning it.

The make method on <class> returns a newly allocated direct instance of its first argument.

Programmers may customize make for particular classes by defining methods specialized on singletons of classes. These methods may reinvoke make on a subtype of the class, or they may obtain the default make behavior by calling next-method.

The default make method signals an error if its first argument is an abstract class. An instantiable abstract class must override this method with its own method for make.

Initialization of Class Allocated Slots

The initalization of slots with allocation class or each-subclass is performed in the following way:

Testing the Initialization of a Slot

A program can test to see whether a slot has been initialized, using the slot-initialized? function, described on page 261. There is no portable mechanism for resetting a slot to the uninitialized state once it has been initialized.

To support the slot-initialized? protocol in a virtual slot, programmers must define a method for slot-initialized? that specializes on the getter of the slot and the class.

Inherited Slot Specifications

An inherited slot specification is used to provide an init specification for a slot inherited from a superclass. It can add an init specification if one was not already present, or it can override an existing init specification.

Inherited slot specifications identify the slot to be modified by the getter name. The inherited slot specification is only allowed if the class does indeed inherit a slot with that getter.

(An inherited slot specification is not required to include an init specification. If it does not, its only purpose is to ensure that the slot is present in a superclass. Because init specifications are not allowed for virtual slots, this is the only valid form of inherited slot specification for virtual slots.)

If an inherited slot specification supplies an init specification, it overrides any init specification inherited from a superclass. This allows the init specification of an inherited slot to be replaced in a subclass, thereby changing the default initial value of the slot.

define class <animal> (<object>)
  slot n-legs, init-value: 4;
end class;
define class <spider> (<animal>)
  inherited slot n-legs, init-value: 8;
end class;

Initialization Argument Specifications

Initialization argument specifications provide options for the handling of initialization arguments. They appear in define class forms, and have a syntax similar to that of slot specifications.

Initialization argument specifications allow the type of an initialization argument to be restricted, they allow an initialization argument to be declared to be required, and they allow the specification of a default value for an initialization argument.

Note that an initialization argument will only be used if it is specified to be the init-keyword of a slot, or if it is used as a keyword argument in an applicable method on initialize. An initialization argument specification can supply a default value for an initialization argument, and it can restrict the type of the argument or make it required, but it does not by itself cause the argument to be used when initializing an instance.

There are two kinds of initialization argument specifications: required initialization argument specifications, and optional initialization argument specifications.

A required initialization argument specification asserts that the initialization argument must be present in the defaulted initialization arguments. The default make method will signal an error if no such initialization argument is present.

An optional initialization argument specification can be used to specify a default value for the initialization argument, using an init specification. When a call to make does not specify the initialization argument, the default make method will add it to the defaulted initialization arguments with the value of the init specification.

The type argument has the same meaning in both kinds of initialization argument specification: it restricts the type of that initialization argument. Note that this is not the same thing as restricting the type of the slot.

The following example shows how initialization argument specifications can be used to override the behavior of a superclass:

define class <person> (<object>)
  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>;

In this example, the <astronaut> class provides default values for the favorite-beverage: and name: init-keywords. In addition to indirectly supplying default values for these slots, this also has the effect of making the name: argument optional in calls to make on <astronaut>. If the call to make does not specify a name:, the name: will be added to the defaulted initialization arguments by the default make method before the defaulted initialization arguments are checked for completeness.

More than one keyword initializable slot may be initialized from the same initialization argument (that is, more than one keyword initializable slot may specify the same init-keyword). However, an error is signaled if a single define-class form has more than one initialization argument specification for the same keyword. An error will also be signaled if a single define-class form has a keyword initializable slot that includes an init specification and also includes an initialization argument specification for the same keyword that is either required or provides a default value. These error situations are all indications of code that can never be reached.

Errata: In the published book, the definition of class <person> is missing a comma between slot name and required-init-keyword:. The definition of class <astronaut> is missing commas in its keyword descriptors, between the keyword and init-value:.

Initialization Argument Inheritance

The inheritance of initialization argument specifications is defined as follows.