Constructors and Destructors
Constructors are subroutines that, if present in a module, are called automatically when the module is created. A subroutine becomes a constructor simply by being named "Constructor".
Constructors are useful for initializing variables, opening files, streams and other I/O connections, launching submodules or for registering the module with external services before the module is fully ready for operation.
Constructors differ from initialization states (the first state to run when a module is created) in that they will occur sooner. The constructor subroutine runs immediately as part of the launch, while there may be a delay before the first state in the module runs. Because constructors were introduced as part of VTS 10.1, you may see the use of a "Ready" flag in older code. This was used as a work-around to ensure that the first state in the module had a chance to run before other code that depended on the completion of initialization tasks would begin.
Example: (Where MyModule is a launched module)
<
MyModule
(
InstanceName;
)
[
Constructor Module;
CapsName;
]
Main [
...
]
<
Constructor
Main [
If 1;
[
CapsName = ToUpper(InstanceName);
Return(Invalid);
]
]
{ End of MyModule\Constructor }
>
{ End of MyModule }
>
The script code that launches the module might look like:
MyObj = MyModule("MyInstance");
InitCapsName = MyObj\CapsName;
In the above example, InitCapsName will be "MYINSTANCE", as the constructor subroutine is executed as part of the line of script that creates the object and assigns it to MyObj. Remember that subroutines take control of executing code until they are finished, thus guaranteeing that CapsName is set by the time the statement InitCapsName = MyObj\CapsName runs.
Constructors execute inside a CriticalSection, so it is impossible for external code to interact with a partially constructed module.
The parent object and caller object of a Constructor is the module being constructed.
Destructors are subroutines that, if present in a module, are called automatically just before a module is slain or otherwise stopped. These ensure that cleanup tasks such as closing files, freeing memory and de-registering a module instance from external services are done even if the module is interrupted unexpectedly. (For example, a user closes a dialog box rather than finishing its task.)
<
MyModule
(
UniqueName;
)
[
Constructor Module;
Destructor Module;
]
Main [
...
]
<
Constructor
Main [
If 1;
[
GlobalDictionary[UniqueName] = Caller(Self());
Return(Invalid);
]
]
{ End of MyModule\Constructor }
>
<
Destructor
Main [
If 1;
[ { UniqueName had been added to a global dictionary as part of MyModule.}
DictionaryRemove(GlobalDictionary, UniqueName);
Return(Invalid);
]
]
{ End of MyModule\Destructor }
>
{ End of MyModule }
>
In this example, GlobalDictionary is a dictionary of all instances of MyModule, keyed by each module instance's UniqueName. The Constructor makes sure that each instance of MyModule is present in that dictionary, and the Destructor removes the instance from the dictionary when the instance is slain.
Destructors execute inside a CriticalSection, so it is impossible for external code to interact with a partially destructed module.
The parent object and caller object of a Destructor is the module being destroyed.