Omnis Technical Note TNLB0001 September 2006
Multiple Libraries and Task Variables
For Omnis Studio 3.x or above.
By Andreas Pfeiffer
There can be many reasons why projects are split into multiple libraries. Maybe you want to build different modules or you simply want to split off certain classes. Using multiple libraries containing different classes can however create communication problems between the different modules, unless you create your libraries in the correct way. The following tech note explains how you can avoid these problems and shows how encapsulation within tasks can be achieved.
Quite often experienced Omnis 7 developers ask me why there are no global variables in Omnis Studio anymore which would enable the programmer to exchange information between different libraries/modules. The variable type with the most global validity is the task variable which can be used by all instances that are located in this task instance.
The purpose of tasks
That is exactly the purpose of a task: to achieve an encapsulation, that is, a separation of instances. As you may know, big parts of the Omnis Studio development environment are written in Omnis itself. For this it is necessary to provide a different task for each part, such as the SQL Browser, the Studio Library Browser, and even for your own library. Sometimes it is necessary to pass information in the form of messages between the different tasks. This is done, for example, when you drag a server table into your library to create a schema class.
In other projects it might be necessary to have much closer communication, in which case you can have different modules running in one task. For this, it is not necessary for each library to have its own task, that is, when you have got one main library and you want to load modules in form of additional libraries you don't need to have a Startup_Task in each of the libraries. Only the main library needs a Startup_Task; you can delete this task from the other modules. When you instantiate a class from an external library in your main library (e. g. open a window) it will automatically belong to the instance of the Startup_Task in your main library, provided that the $external property of the window class is set to kTrue. This ensures that all task variables of the Startup_Task in your main library are available in your window instance. However if the window is called from another task instance (e.g. from the Startup_Task of your module library) it will be in that instance.
You will have noticed that the task variables in the task of your main library are not visible in the variables declaration pane in your window (which is located in a different library). The reason is that Omnis cannot know to which task instance the window instance will belong. But fortunately we can inform the window class about it. To do this go to its property $designtaskname and simply set the library name followed by a dot and then the name of the Startup_Task of your main library. And now you can see your task variables in your variable declaration as well as in the Omnis Catalog (F9). Note that the window has to be opened from an instance which already belongs to this task instance. A simple Ctrl./Cmd.-T will not work here, that is, you won't have the variables available.
Use task variables economically
In order to prevent an unnecessary inflation of task variables you should use them economically. Before you create a task variable you should always think whether or not you really need it. Is the content, that is, what the task variable represents, really global for the task? If so you may need a scalar variable, or would it be better to use an object?
I personally only use about three task variables in my projects. All three of them are of the type object. For example, I use a 'user object' since a user has a global identity for a task instance. It could never happen that two or more users would work at the same time in the same task instance. But as I am using multiple get functions in my user object (e. g. UserObj.$getUserName() etc.) I can fetch any information from my user object without having to use many task variables.