In Visual Lansa the concept of component scope is often misunderstood. I have come across many component definitions that misuse the scope parameter. Often, it is because definitions are copied between Owner Components that do not function the same way and analysis is not done to evaluate the proper component scope.
A defined component in Visual Lansa may be given different levels of Scope within the application; “The SCOPE parameter is used to create component instances that are shared between different instances of component owners” (LANSA User Assistance V11 SP5, Technical Reference Guide 8.4.1). The SCOPE parameter can be specified as *INSTANCE, *LOCAL, *DEFAULT, *SHARED, or *APPLICATION.
*INSTANCE – When a component is defined with parameter SCOPE(*INSTANCE) a new instance of the component is created for each owner component
*LOCAL – When a component is defined with parameter SCOPE(*LOCAL) a new instance of the component is created every time an Event, Method, or Property Routine is executed; as such, this value is only valid when the component is defined immediately after a EVTROUTINE, MTHROUTINE, or PTYROUTINE command.
*DEFAULT – When a component is defined with parameter SCOPE(*DEFAULT) the value is determined from the position of the component definition. Components defined immediately after the BEGIN_COM command are interpreted as *INSTANCE, components defined immediately after EVTROUTINE, MTHROUTINE, or PTYROUTINE commands are interpreted as *LOCAL.
*SHARED – When a component is defined with parameter SCOPE(*SHARED) only one instance of the component is created for all owner components of the same class. Owner components of different classes do not share component instances defined as scope *SHARED.
*APPLICATION – When a component is defined with parameter SCOPE(*APPLICATION) only one instance of the component is created for all owner classes within the application, as such all DLL’s required to implement the defined component and owner component will remain in memory for the lifetime of the component instance and possibly the lifetime of the application.
The following is a visual illustration of different scoping parameters demonstrated with a visual component. The same principal applies for non-visual components. In these examples a parent form and child form(s) of different classes dynamically create instances of a calendar control.
SCOPE(*INSTANCE)
All components reference their own instance of the calendar control. As such, when a child component closes the reference to the calendar control is set to null and its DestroyInstance event is signaled. This allows the child forms handle count to reach zero at which point its own DestroyInstance event is signaled. The DLLs for both the calendar control and form will be unloaded during garbage cleanup.
SCOPE(*SHARED)
When the calendar control is defined as SCOPE(*SHARED) a new instance of the component is created for each owner component class; because Parent Form and Child Form are separate classes they do not share an instance of the calendar control. Notice that only one Child Form has a visible calendar control, because the calendar control is shared between the two like classes it can only be visible on one…because the calendar control can only have one owner component. This is not an issue for non-visual components but further illustrates the point that there is only one shared instance. In this case the calendar control will not be destroyed until its reference is set to *Null by both Child Forms, the DLLS for the child forms and calendar control will also not be unloaded until both references are set to *Null and both child forms are closed.
SCOPE(*APPLICATION)
When the calendar control is defined as SCOPE(*APPLICATION) a single instance of the component is created for all components within the application (that are defined as SCOPE(*APPLICATION). The single component instance is shared regardless of owner component class. Owner components containing components defined as SCOPE(*APPLICATION) will not be destroyed (and DLLS will not be unloaded) until all references of the Defined Component within the application are set to *Null.
The first question to ask when determining the proper component scope is ‘Is the component used in multiple owner components?’ – If No, then the Defined Component should be SCOPE(*INSTANCE) when defined after a BEGIN_COM or SCOPE(*LOCAL) when defined within an event, property, or method routine…this is the default component scope.
If a component is used in multiple owner owner components ask ‘Are the Owner Components main features of the application that will exist as long as the application is running?’ – If No, then the Defined Component should be SCOPE(*INSTANCE) when defined after a BEGIN_COM or SCOPE(*LOCAL) when defined within an event, property, or method routine…this is the default component scope.
If the Owner Components are main application features that should share an instance of the Defined Component ask ‘Are the Owner Components of the same component class?’ – If Yes, then the Defined Component should be SCOPE(*SHARED); If No, the Defined Component should be SCOPE(*APPLICATION).
A great deal of thought must be given to the Scope parameter when defining components within a large application. Allowing components within an application to share instances of a component provides improved performance by avoiding multiple CreateInstance routines, but it also may prevent DLLs from being unloaded and system resources being freed.
