Chapter 3 The Application Description Language

3.25 Object Initialization

An ADL description of an AM2 application consists of class definitions and initialized instances of those classes. Most class definitions include object members that are instances of other classes. The initialization of these instances is what gives an AM2 application its particularity. It is whatmakes one interface screen different from another and what distinguishes a particular interface button from the next.

The ADL provides several mechanisms for initializing object instances. Each of these is optional, and each is applied successively. The initial state of an object is the result of these cumulative and possibly overlapping initializations. The complete initialization sequence for an ADL object is as follows.

1. The ADL creates the object. That is, the ADL allocates storage for the object so it has an address.

2. The ADL creates and initializes all bases and members recursively, each set in declaration order. (Creation means allocation, as discussed in the first step. Initialization refers to all of the steps discussed in this list.)

3. A constructor message is sent to the object and handled if the corresponding method exists. If a special constructor is specified in the object definition or new statement, that is the constructor message sent, it must be handled or the system generates an error. If the object definition or a new statement does not specify a special constructor, then the default Construct message is sent without arguments. This message is optional, so the system does not generate an error if there is no corresponding Construct handler.

4. The optional initializor block, if it exists, executes as if it were a method of the object being initialized. All assignments in the initializor block are treated as foreign.

5. The ADL queries the asset manager about the object, and applies any assets that pertain to the object.

6. The ADL sends an optional Init message to the object. If there is an appropriate handler, it executes. Otherwise it is ignored.

Simple Initialization Example
class MyClass
{

Member Declarations;
upon Construct { ... }

upon Create : handle h { ... }

on Init { ... }
};

MyClass aInstance { Initializor Block};

MyClass {'Create, &aInstance} => bInstance;

Let us illustrate this sequence with a few examples:

In this case, aInstance and bInstance are instances of the class MyClass. We
initialize aInstance in the following steps:

1. Create the class instance aInstance.

2. Create and initialize all members of aInstance using this procedure starting at the first step.

3. Call the Construct method on the object aInstance since there is no special constructor specified.

4. Execute the initializor block that follows the declaration of aInstance as a scope (see Section 3.26, "Scope" page 52). Member reference follows the pattern of a method inside MyClass. That is, the user may refer to members by simple member name rather than the combination aInstance.memberName. Member protection, however, follows the rules for an external reference. Assignment to class members from within an initializor block invokes the appropriate Set_ method.

5. Consult the asset database to locate any resources that apply to the class MyClass and the instance aInstance, and apply them to the instance.

6. Call the Init method.

The initialization of bInstance is similar except that it calls the special constructor Create instead of the default Construct, and it does not execute an initializor block.

Constructor methods require comment since their definition uses a special syntax. In general, bases need not know anything about their derived instances. But there are circumstances where this is not the case. For instance, windowing systems generally refuse to create widgets without knowing the parent widget. In the ADL, widget containment is implemented as class membership. That is, a manager widget contains its child widgets as members. If those child widgets are subclasses of the base wrapped widgets, then the initialization of the subclassed child widgets must inform the wrapped bases of their parent during processing of the constructors.

As an example, consider a specialization of the base button class, XFbutton, called ExitButton. ExitButton has special behavior, background color and label. If we go to create a manager that contains an exit button, then the constructor for this ExitButton must somehow inform the base XFbutton of its manager parent. The ADL distinguishes constructor method definitions in order to add the mechanism to make this possible. Figure 3.48 illustrates this.
Constructor Method Syntax
upon selector [: type1 arg1, ... , typen argn]

[init { CtorMessage1 => base1, ... , CtorMessagen => basen }]
{
Method Declarations
Method Statements
}

Constructor definitions start with the keyword upon instead of on. The constructor body can be preceded by an optional init block that specifies constructor calls for direct bases. The constructor messages in this block must correspond to special constructors defined in the bases. The constructor messages in the init block are evaluated in the scope of the constructor execution so they have access to the constructor arguments.

The SetAttributes (see Figure 3.37, "Sample SetAttributes Call" page 39) method alleviates a scoping problem for constructors and initializor blocks. Initializor blocks provide the application developer far greater flexibility in initializing object members than constructors, but because they have object method scope, they cannot refer to variable values from the scope in which the object is being initialized. A special constructor that takes an attribute/value list as its sole argument can import an arbitrary set of values from the initializing scope and use them to initialize the object, thus circumventing the fixed argument list of the special constructor and the restricted scope of the initializor block.


AM2 Documentation - 19 NOV 1996

Generated with Harlequin WebMaker