317 Library: Principle of Usage
VERSIONS: All ? - written for Paradox 5

SUBJECT: Library - Principle of Usage
BY: Tarik Ghbeish - Borland

I thought I would mention a few principles of library usage in brief.

Libraries:

When:
  • When you're running out of symbol table space in the current form. It is important that you plan ahead. It is a lot easier to use a library when you intended to do so when you started. Moving code to a library can be a headache when you have your form cross referencing you code willy nilly. On the other hand, it does tend to clean up code duplication on the form, so it can be quite a good thing. I often use libraries because they lend themselves to good, reusable design, rather than because I'm running out of space.

  • Anytime you've written a custom method, it can be a candidate for a library call. Custom methods are especially important if you are going to use the code more then once, such as a search routine, or a technique to change the look of your form. I use custom methods to enable and disable field and button objects in my applications.

  • Anytime you need to share code between two different forms. My enable/disable routines are examples of that. I have a central library that I prepared which handles all common services I might need in my apps: error handling, hot key support, common routines like sorting, listing files, filling list and drop-down list objects, etc. This really MASSIVELY speeds up app dev when you have finally built a library that does what you need.

How:
  • Basics - create a method in the library that does what you need. Copy that method header to the Uses statement (minus the method keyword) of whatever form or library you're going to use it in. Use a library variable to open the library (lib.open(...)) and call the method (lib.methodName(...)). Ok, this part is relatively simple and the books cover it.

Issues:
  • Referencing objects on the form from a library - libraries cannot see objects on a form since they are not a part of any particular form and can in fact be used from more than one form at a time. There are numerous ways to reference objects on a form from the library, however:

  • self - refers to the object which calls the library method. You can use this to change the objects color, attach to the objects parent object (ui.attach(self.containerName)) so that you can walk up the object tree to find other objects.

  • formVar - if the names are hard coded, you can use formVar.attach() with no parameters to attach to the form that is currently calling the library. You can then reference objects on that form using techniques like formVar.ObjectName. This approach can lock the code into use only on forms that have these objectnames, so be aware. It is important when referencing objectnames to avoid reserved ObjectPAL words like TYPE, SUBJECT, NAME (not a reserved word, but a property that can become confused when your object is called NAME). My trick is to use a naming scheme for all objects I intend to refer to. All field are prefixed with fld, all buttons with btn, etc. So the fields become fldType, fldName, fldSubject.

  • passed UIObject handle - this is my favorite. The form can pass the handle (name) to the UIObject and than you can do anything you want with it. For instance, you can check the class of the object (ui.class) to discover if it is a button or field or text, etc., and then you can perform an operation on that object based on it's class. Sometimes I need to refer to several objects at once. I either make each of these a parameter that I pass to the custom method, or if there are a large number of objects, I pass a handle to the container and attach to the rest in the method (ui.attach(passedUI.objectName)).

  • Make your code carefully generic - you can do this by passing parameters which you can refer to to decide how you are going to perform processing. In my enable/disable code, I could pass an object handle which is analyzed to decide if the object is a field or button. Depending on which it is, I know how to enable or disable the object. One method call to perform two different, though related tasks. A second parameter is a logical var which indicates whether the object should be enabled or disabled, so rather than two method calls (one to enable, one to disable), I have one, It makes for concise programming.

  • Pass by VAR any references that need to changed - this is VERY important if you want to pass a tcursor or array to a library, perform some processing, and then be able to inspect the tcursor or array and see the changes based on the operation you performed. A common technique would be to pass a tcursor (by VAR), a fieldname, perhaps an indexname, and a value, and have the tcursor perform a locate. Since all references are passed into the method, the tcursor doesn't even have to know what table is being searched. It can use method calls to set the index (if passed), and perform a locate on the field, returning true or false. The form could then know that the tcursor was pointing at the correct record and use it immediately. Generic locate code.

  • Make sure that Uses and method headers match - these are often being adjusted and are a common problem when they get out of sync. Since they can look so similar, the best solution is to copy and paste from the method to the Uses.

  • Always use the library var to reference the method - this may sound like basic stuff, but it still happens to me and is a very common, frustrating error. One way to handle it is to sort your libraries by type of service and name your vars to remind you that this is an object you are pulling methods of that type out of. I use a object library for object manipulation, a services library for common services like file name analysis, etc.
There's plenty more, but I've got work to do.

To index