Library Facility

From BR Wiki
Revision as of 19:29, 15 April 2013 by 66.17.154.248 (talk) (Created page with "Business Rules! now includes a comprehensive '''Library''' Facility. Similar to DLL (Dynamic Link Libraries), the Business Rules! Library Facility enables [[user-defin...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Business Rules! now includes a comprehensive Library Facility. Similar to DLL (Dynamic Link Libraries), the Business Rules! Library Facility enables user-defined functions to be placed in a program ("library") that is separate from the main program. The library may be loaded "resident" (staying loaded regardless of the status of the main program), it may be loaded "present" (remaining active in current memory as long as the main program is active), or it may be loaded "as needed" (loaded when needed to execute a function, then unloaded as soon as the function has been executed).

A library is any Business Rules! program that contains library functions. A library must be identified to Business Rules! before a program can execute any of its functions. When a library is identified, Business Rules! adds its name to an internal table of library names. This table identifies the names of all the libraries that should be searched whenever a library function that is not yet linked to a library is called.

Business Rules! places no limits on the number of libraries that may be loaded into memory at one time. Business Rules! provides for maximum memory usage and performance flexibility by allowing libraries to be identified and loaded into memory via three different methods: the resident method, the present method and the as-needed method. See the separate descriptions below for specific information about each type of library.

Advantages

Some of the significant advantages of placing user-defined functions in a library rather than keeping them in the main program are as follows:

1.) Reduces the size of executables - its no longer necessary to include a standard set of user-defined functions in every program in your application. For some applications (which may include literally hundreds of copies of the exact same code), the potential savings in disk space are tremendous.
2.) Saves maintenance time - If you're in the habit of duplicating user-defined functions in every single program that needs them, you know what kind of effort it takes to make (and distribute to your clients) even a one-line change to a function. With Business Rules Library Facility, you make the change only once, and you replace only one program at the client's site.
3.) Encourages use of programming standards - The use of library functions for a standard routine is a great way to encourage programming consistency and the setting of standards among your programmers.

Library Function

A library function is a specially defined user-defined function; it exists in a program which is frequently separate from the main program, but it may exist in the main program as well.

To qualify as a library function, a user-defined function must simply utilize the DEF statement's LIBRARY keyword. The following is an example of a library function definition:

52400 DEF LIBRARY FNRESLIB2
52500 PRINT "This is a library function"
52600 FNEND

Executing a library function is a two-step process. First, the program executing the library function must name the function in a LIBRARY statement, which establishes either named or unnamed linkage. Second, the program must call the library function; this may be accomplished using any of the same methods that is available for calling other user-defined functions. In the following example, line 01000 uses the LIBRARY statement to establish named linkage between the function FNPRESLIB2 and the library PRESLIB. Line 01100 causes the library PRESLIB to be loaded into present memory (if the library does not already exist in memory), then executes FNPRESLIB2.

01000 LIBRARY "PRESLIB": FNPRESLIB2
01100 LET FNPRESLIB2

Implementation Considerations

Business Rules Facility was carefully designed to offer a great deal of power and flexibility. Before you begin implementing this capability into your existing applications and ongoing development, ADS recommends that you consider the following:

1.) Should your libraries remain resident?

Business Rules allows for libraries to remain resident in memory (providing maximum performance) or to be loaded and released as needed (providing best utilization of memory). Be sure to select the method or combination of methods that's best for your applications.

2.) Will you use multiple versions of the same function?

Since maintaining more than one version of a function is one method of controlling program options, Business Rules' rule for library selection has been established with care. You should carefully review these rules and the ways in which multiple libraries can be of use to you as you plan your implementation.

Until you feel comfortable with the intricacies of the Business Rules Library Facility, ADS recommends that you give every library function a name that is unique from every other library function.

3.) Do your existing functions utilize global program variables?

Unlike local user-defined functions, library functions that exist in a program separate from the main program cannot access main program variables globally. They have to be specifically passed. You should carefully review your usage of global variables before moving local functions into separate libraries.

As needed Library

An as-needed library is loaded and unloaded as needed for execution of specific functions. Loading a library only when it is needed allows the program to conserve memory usage.

Each library has its own global variables that are separate from the main program's variables. Global Variables in an as-needed library are cleared each time a function call to the library is completed and the library is subsequently unloaded from memory.

Programs can indicate that a library is to be loaded as needed by specifying the LIBRARY statement with both the RELEASE parameter and function names. This causes Business Rules to establish named linkage between the specified function(s) and the specified library, but it does not actually load the library. (The library is loaded only when one of the as-needed library's functions is actually called.) In the following example, line 00280 establishes linkage between the library ASNLIB and the function FNASNLIB1. Line 00290 causes the following to occur:

1.) Load ASNLIB into memory,
2.) Execute the function FNASNLIB1,
3.) Remove ASNLIB from memory.
00280 LIBRARY RELEASE,"ASNLIB": FNASNLIB1
00290 LET FNASNLIB1

Linkage Reassignment and Detachment

Once Business Rules has established linkage between a specific function and a specific library, the linkage remains active until a specific event causes it to become reassigned or detached.

REASSIGNMENT

As noted previously, the LIBRARY statement may be used to establish linkage between a function and the library from which it is to be called. When the named LIBRARY statement is used, linkage is directly established between the named library and the named function(s). When the unnamed LIBRARY statement is used, Business Rules searches for the function according to some pre-set guidelines and assigns linkage to the first library within which the function definition is found.

Once a function has actually been linked to a library, the only way to subsequently establish linkage between the same function name and a different library is to execute another LIBRARY statement that names the same function and a different library. When all of a present library's linked functions are reassigned; the library is automatically removed from memory. When all of a resident library's linked functions are reassigned; the library may be removed from memory with the CLEAR command.

In the following example, lines 01100 and 01200 load the libraries PRESLIB1 and PRESLIB2 into present memory. Line 01300 uses a named library statement to establish linkage between PRESLIB1 and the function FNASSIGN, and line 01400 actually executes FNASSIGN from the PRESLIB1 library. Line 1500 then re-assigns linkage of FNASSIGN to the library PRESLIB2, and line 1600 executes FNASSIGN from the PRESLIB2 library.

01100 LIBRARY "PRESLIB1":
01200 LIBRARY "PRESLIB2":
01300 LIBRARY "PRESLIB1": FNASSIGN
01400 LET FNASSIGN
01500 LIBRARY "PRESLIB2": FNASSIGN
01600 LET FNASSIGN
DETACHMENT

Regardless of how a library is loaded (resident, present or as needed), all linkages are detached at the time that the main program ends.

There is no other way to completely detach a linkage other than ending the main program.

Present Library

A present library is a library that is loaded to remain in memory as long as the main program is active or until all linkages that have been established for the library are reassigned.

Each library has its own global variables that are separate from the main program's variables. Global Variables in a present library are cleared when the main program ends.

A library can be loaded present through three different methods:

  1. .The first method is to specify a LIBRARY statement that identifies a library name but no function names. When this method is used, the library is loaded at the time that the LIBRARY statement is executed. For example, when the following statement is executed, the CURLIB library is immediately loaded into memory:
00210 LIBRARY "CURLIB":
  1. .The second method of loading a library present is to specify the LIBRARY statement with both a library name and function names. When this method is used, the library is loaded the first time one of the specified functions is called. In the following example, line 00210 establishes linkage between the function FNCURLIB1 and the library CURLIB.

Line 00220 causes the following to occur:

1.) The library CURLIB is loaded as a present library,
2.) The function FNCURLIB is executed.
00210 LIBRARY "CURLIB": FNCURLIB1
00220 LET FNCURLIB1
  1. .The third way to end up with a library loaded present is to execute a CLEAR STATUS command on a library that has already been loaded resident and has attached functions, thus turning it into a present library.

Resident Library

A resident library is a library program that is loaded to remain in memory, regardless of the status of the main program. It does not get removed from memory until it is explicitly cleared or until the Business Rules session is terminated. Loading a library resident saves the overhead associated with loading a library each time it is needed.

Each library has its own global variables that are separate from the main program's variables. Business Rules allows resident libraries to handle their own global variables in any of three different ways:

1.) Globals may be cleared when the main program ends,
2.) Globals may be retained irrespective of the status of the main program, or
3.) Globals may be cleared after each function call to the resident library.

The resident status of a resident library can be removed (thus changing the library into a present library) through the use of the CLEAR STATUS command.

A library can be made resident through use of the enhanced LOAD command. However, it is important to understand that functions cannot be executed from any library -even a library that has been loaded into resident memory -until a LIBRARY statement names the functions to be executed and establishes linkage (either named or unnamed) between the named function and the resident library.

In the following example, line 00130 causes RESLIB to be loaded into memory as a resident library. Line 00140 establishes named linkage between the function FNRESLIB1 and the RESLIB library. Line 00150 executes the function FNRESLIB1.

00130 EXECUTE "LOAD RESLIB,RESIDENT"
00140 LIBRARY "RESLIB": FNRESLIB1
00150 LET FNRESLIB1

Comparison of User-Defined Function Features

The following table illustrates the similarities and differences between regular user-defined functions (non-library) and library user-defined functions.

File:Help0185.jpg
File:Help0186.jpg
File:Help0187.jpg

Variable Usage

Before you start placing all your existing user-defined functions into separate libraries, you should fully understand how library functions deal with global variables.

This section will focus on three main points:

1.) How a main program and a library function can communicate,
2.) How functions within a library communicate, and
3.) When global variables are cleared for a library program.

How main programs and library functions communicate

Business Rules programs communicate with regular user-defined functions via passed parameters, the returned function value, and global variables (variables not passed in the parameter list). All of these same communication options are available for library functions that are defined within the main program. However, only the first two options are available to library functions that are separate from the main program. These functions cannot access the main program's global variables because global variables are only available to routines and functions, which are defined within the same program. As a result, user-defined functions, which are held within a main program, may need to be reviewed for their global variable usage before they are changed to library functions and placed into a separate library program.

If a program needs to communicate a large number of standard values to a library function, consider using an initialization function to pass the values to the library program. Then have the initialization function assign the passed values to global variables in the library so they will be available to all functions in the library.

How functions within a library communicate

Within each library, all functions share variables which are global to that library, and library global variables generally retain their values between function calls. (The exception is when the RELEASE keyword is used on the LIBRARY statement, which is accepted both for resident and as-needed libraries; in this case, global variables are cleared after each function call.)

The point at which globals are cleared for a library program varies according to several factors. See below for more information.

When global Variables are cleared

The point at which a library's global variables are cleared depends on how the library was loaded and -in the case of resident libraries-what options are used.

{\b Main program library} - For library functions that are defined within the main program, globals are cleared when a new main program is started or when the current main program is explicitly removed from memory.

Resident library - When a library is loaded resident, global variables may be cleared in any of three ways:

Default By default, Business Rules clears a resident library's global variables when the main program ends.
Retain When the OPTION RETAIN statement is used in a resident library program, the library retains its global variables irrespective of when the main program ends. The only way to clear globals when this statement is used is to CLEAR the library from memory or to reload it with the LOAD RESIDENT command. Remember that the library must be loaded resident for the OPTION RETAIN statement to have any affect.
Release When a resident library is named on a LIBRARY statement with the RELEASE keyword, the library's global variables are cleared after each function call to the library. This capability is provided so that the decision to load a library resident or as-needed can be made on a case-by-case basis; the program code can remain the same (because Business Rules handles the variables the same) regardless of whether the library is loaded resident or as-needed.


{\b Present library} - When a library is loaded present, global variables are cleared when the main program ends.

{\b As-needed library} - When a library is loaded as-needed, global variables are cleared after each function call to the library.

The following table summarizes the information presented above. The keywords used in the "When globals are cleared" column are the same keywords used in the STATUS LIBRARY display (second column from right) to identify when variables for the listed library will be cleared. (See the "STATUS" command in the Commands chapter for complete information about this display.) The keywords are defined as follows:

RUN Globals are cleared when new main program is run.
END Globals are cleared when main program ends.
EXIT Globals are cleared after each function call to the library.
RETAIN Globals are retained, irrespective of main program status.


File:Help0188.jpg

Additional Processing Consideration

Active procedures and opened files are not affected by library function calls, unless the library issues commands that specifically affect them. This includes PROCERR settings.

A nice aspect of library functions is the capability of a program to call a library function, which, in turn, calls a function in the main program. This supports the concept of manager functions that provide overall functionality while the main program fills in the details that may vary from program to program.

The way to permit library routines to be overridden (functionally replaced) by corresponding functions in the main program is to have the library include those functions in a LIBRARY statement that doesn't specify a library name. Then have the library execute that statement after the main program has started. The library will then attach the library function in the main program instead of its own, even if a copy of the function exists in the library, because the main program is always regarded as having been loaded last for purposes of resolving unnamed library searches.

Note that if a LIBRARY statement within a resident library creates linkage and then the main program ends, the linkage is broken and that LIBRARY statement must be re-executed before the function can be called again by the resident library.

With respect to speed, parameters should be passed by reference (using the & in front of the variable name in the DEF statement) wherever possible. This avoids needless allocation of memory and copying of data, which is a significant part of function call processing.

If you want to avoid the processing time required to load a library until a function within it is called, simply name the library and function on the same LIBRARY statement. However, if you want to be sure that the named functions exist within the library, first load the library with a statement that contains no function names. This will cause the library to be loaded at the time the LIBRARY statement is executed. Then when the LIBRARY statement containing the function list is encountered, the library (which is now in memory) will be checked for the presence of each function.

It should be emphasized that executing a LOAD command does not establish function linkage. A subsequent LIBRARY statement must be processed to establish such linkage.

When replacing a resident library with a different library, the first library should be cleared with a CLEAR command to free its memory before loading the second library.

Updating a library (with the REPLACE command) has no effect on application environments until the library is (re)loaded.
If a LIBRARY statement contains the name of a local function that is defined as non-library, a "duplicate function definition" error is generated when the program is run or saved.

If a LIBRARY statement refers to a library without RELEASE and another statement refers to the same program with RELEASE, an error is generated. Also RELEASE cannot be specified for any library with the OPTION RETAIN statement.

If a function in the main program, defined with the LIBRARY keyword, is called from within a library (a condition referred to as library loopback), the main program uses a fresh for-next stack.
Therefore, pre-existing for-next processes are not recognized until the library returns normally to the main program.

If more than one DEF LIBRARY statement for the same function name appears in a program, the lowest numbered definition will be used. More than one non-library DEF for the same variable is no longer permitted.

Memory fragmentation can occur if a library is loaded resident while other programs are in memory, and then the main program chains leaving files open through either the CHAIN FILES statement, or having files open NOCLOSE. To avoid this problem, if you use CHAIN FILES or NOCLOSE, load your resident libraries before running application programs.

Alternate libraries can be interrogated with function key 9 during a program pause.

Editing Active Libraries

When both a main program and a library program that is separate from the main program are active ( a function in the library program is currently being executed), the LIST command will display the contents of the library program. When functions in multiple library programs are active, the program with the most recently called function will be displayed.

It is important to note that the only way to save changes made to a library program that has been activated by a main program is to list the library to a file and reload it from source later on. Because of this, it makes sense to develop a new library function first within the main program. Then once you've completed the testing and debugging process, you can break it out and test it as a separate library function.

Linkage

When used to its full potential, the Business Rules Library Facility enables multiple versions of the same function (with the same name) to exist in different libraries, all of which may be loaded into memory. The actual library that is used for a specific function call is determined according to Business Rules rule for linkage, which is the process of associating a function name with a library name.
Business Rules keeps tracks of established linkages in a table that it references each time a function is called.

The LIBRARY statement may be used to establish linkage in one of two ways: the named method, or the unnamed method. These methods are defined as follows:

Named

The LIBRARY statement explicitly links one or more specific functions to a specific library. This is the most efficient and foolproof method for assuring that the library function you wish to use gets executed.

In the following example, the functions FNRESLIB1 through FNRESLIB5 are explicitly linked to the library MAIN. When any of these functions is called, Business Rules will automatically execute them from the MAIN library. (Regardless of whether or not any other library currently in memory also contains functions by the same name.)

50300 LIBRARY "MAIN":FNRESLIB1,FNRESLIB2,FNRESLIB3,FNRESLIB4,FNRESLIB5
Unnamed

The LIBRARY statement names the desired library functions and leaves it to Business Rules to determine which of the currently identified libraries they should be linked to. This determination is made according to the pre-set guidelines described below. The unnamed method of linkage is useful when your development methodology involves using multiple versions of the same function to control program options and features.

When the unnamed method is used, Business Rules first searches the main program, then each library that is currently either resident or present (in last loaded, first searched order) for each function listed on the LIBRARY statement. Once Business Rules finds the function, the linkage is established, and -unless the linkage is explicitly changed with another LIBRARY statement or detached because the main program ends -all future calls to the same function will continue to utilize the same linkage. Note that Business Rules does not search as-needed libraries when the unnamed method of establishing linkage is used. Also, it is important to understand that it can take significantly longer to establish linkage using the unnamed method of linkage than with the named method of linkage.

In the following example, line 01000 loads RESLIB as a resident library. Lines 01100 and 01200 load PRESLIB1 and PRESLIB2 as present libraries, and line 01300 names ASNLIB as an as-needed library. The LIBRARY statement on line 01400 establishes unnamed linkage for the function FNALIBI. When line 01500 is executed, Business Rules searches the currently loaded programs in the following order for FNALIBI: Main program, PRESLI2, PRESLIB1, RESLIB. Note that ASNLIB is not considered for this search because it is not currently loaded in memory.

01000 EXECUTE "LOAD RESLIB,RESIDENT"
01100 LIBRARY "PRESLIB1":
01200 LIBRARY "PRESLIB2":
01300 LIBRARY RELEASE,"ASNLIB": FNASNLIB1
01400 LIBRARY : FNALIBI
01500 LET FNALIBI

Status Library

Business Rules STATUS LIBRARY command may be used to display a table that identifies all the linkages that are currently active for each library. See "STATUS" in the Commands chapter for more information. For information about releasing and/or changing library linkages, see the term Linkage reassignment and detachment below.

Sample Program

The following two sample sections of code are, for convenience purposes, labeled "Main Program" and "Library". The Main Program references two functions (FNSEND and FNRECEIVE), which are located in the Library. Line 50 of the Main Program establishes the function linkage; line 70 prompts for a message; and line 110 calls the FNSEND function, which is defined on line 30 of the Library.

FNSEND opens the communications port and sends the operator-specified message to the terminal connected to the port. The Main Program then calls the FNRECEIVE function, which is defined on line 80 of the Library. This function waits up to 15 seconds for a response (by default), returns the response in the parameter, and returns its length as a function value. Finally, the Main Program prints the response or the message "No Response".

MAIN PROGRAM
00010 ! MAIN PROGRAM
00020 !
00030 DIM MESG$*60, RESPONSE$*120
00040 !
00050 LIBRARY "TOOLS\LIB1": FNSEND, FNRECEIVE
00060 !
00070 PRINT "Specify Message"
00080 LINPUT MESG$
00090 IF LEN(MESG$) = 0 THEN STOP
00100 !
00110 LET FNSEND(MESG$)
00120 !
00130 IF FNRECEIVE(RESPONSE$) THEN !:PRINT RESPONSE$ !:ELSE !:PRINT "No Response"
00140 GOTO 70
Library:
00010 ! LIB1
00020 !
00030 DEF LIBRARY, FNSEND(MESSAGE$*60)
00040  IF NOT COMM OPENED THEN !:OPEN #40: "NAME=COM2:, FORMAT=ASYNC,BAUD=2400",DISPLAY, OUTIN !:COMM OPENED = 1
00050  PRINT #40: MESSAGES$
00060 FNEND
00070 !
00080 DEF LIBRARY FNRECEIVE(&RESP$)
00090  LINPUT #40: RESP$ IOERR 100
00100  FNRECEIVE = LEN(RESP$)
00110 FNEND

Tips for implementing Library Functions in Existing Applications

As mentioned above, it is important that you consider your current usage of global variables before converting your existing user-defined functions into library functions and placing them into a separate program. This section provides some examples of how you can modify existing applications to utilize library functions, even if the existing applications currently access or modify user-defined function variables from outside the function. Other examples shown in this section demonstrate how you can turn an entire program (such as a client maintenance program) into a library function that a user can invoke at will from within another program (such as order entry) and provide some tips on implementing libraries for programs that use FNSNAP! tools.

Example 1

Separating main program logic from user-defined functions
The following is a very simple example of a program that uses a user-defined function.

ORIGINAL PROGRAM
00010 PRINT "Enter estimated number of pages:"
00020 INPUT PAGEEST
00030 LET FNDOCEST(PAGEEST)
02000 DEF FNDOCEST(&PAGEEST)
02010  LET WRITETIME=(PAGEEST*2)*1.15 ! Two hours per page, plus 15% for index
02020  PRINT "Documentation estimate is: ";WRITETIME;"hours"
02030 FNEND

The steps you would need to take to separate the function into a separate library and enable the main program to call the function would be as follows:

1.) Place the user-defined functions into their own program.
2.) Modify the DEF line for each of the functions in the new library program to utilize the LIBRARY keyword (demonstrated in line 02000 of the library program below).
3.) Delete the separated functions from the main programs that are to use the new library.
4.) Add a LIBRARY statement to the main program that names each function that is to be called from the library program (demonstrated in line 00005 of the main program below).
MAIN PROGRAM
00005 LIBRARY "howto1nl" : FNDOCEST
00010 PRINT "Enter estimated number of pages:"
00020 INPUT PAGEEST
00030 LET FNDOCEST(PAGEEST)
LIBRARY PROGRAM
02000 DEF LIBRARY FNDOCEST(&PAGEEST)
02010  LET WRITETIME=(PAGEEST*2)*1.15 ! Two hours per page,lus 15% for index
02020  PRINT "Documentation estimate is: ";WRITETIME;"hours"
02030 FNEND
Example 2

Function uses global variables established by main program

In the following program, the global variable PAGEEST is established by the main program logic on line 00020. This same global variable is accessed by the user-defined function at line 02010.

MAIN PROGRAM
00010 PRINT "Enter estimated number of pages:"
00020 INPUT PAGEEST
00030 LET FNDOCEST
LIBRARY PROGRAM
02000 DEF FNDOCEST
02010  LET WRITETIME=(PAGEEST*2)*1.15 ! Two hours per page,plus 15% for index
02020  PRINT "Documentation estimate is: ";WRITETIME;"hours"
02030 FNEND

As there is no way for a main program to share its global variables with a library function contained in a separate program, this program must be modified before it can be separated into "main" and "library" programs. In the following example, line 02000 has been modified (as shown in italics) to pass the PAGEEST variable by reference, thereby causing the library function to use the main program's copy of the variable.

MAIN PROGRAM
00010 PRINT "Enter estimated number of pages:"
00020 INPUT PAGEEST
00030 LET FNDOCEST(PAGEEST)
LIBRARY PROGRAM
02000 DEF FNDOCEST(&PAGEEST)
02010  LET WRITETIME=(PAGEEST*2)*1.15 ! Two hours per page,plus 15% for index
02020  PRINT "Documentation estimate is: ";WRITETIME;"hours"
02030 FNEND
Example 3

Existing program queries function variable from outside function
This example shows the same starting program as shown in Example 1, except that line 00040 has been added to demonstrate a situation where the main program logic queries (without changing) a variable that has been established by the user-defined function. This programming technique also is not allowed when functions are separated into library programs, as there is just one way (via the function variable) for a separate library function to pass a value back to the main program.

MAIN PROGRAM
00010 PRINT "Enter estimated number of pages:"
00020 INPUT PAGEEST
00030 LET FNDOCEST
00040 IF WRITETIME>8 THEN PRINT "Total days: ";WRITETIME/8
LIBRARY PROGRAM
02000 DEF FNDOCEST
02010  LET WRITETIME=(PAGEEST*2)*1.15 ! Two hours per page,plus 15% for index
02020  PRINT "Documentation estimate is: ";WRITETIME;"hours"
02030 FNEND

When starting new programming projects that are to utilize Business Rules Libraries, ADS recommends against the programming technique shown here. However, if your programs already use this technique and you want to utilize the benefits of libraries with as little work as possible, you could change the programs in the manner shown below.

The following two code sections show the original program as it would be when split into main program and library, and with a "rigged" technique for the program to get the value of the queried variable from the library. The "rig" is that all references to the WRITETIME variable in the main logic have been changed to FNWRITETIME, and FNWRITETIME has been added to the library to query the value of WRITETIME and pass it back to the main program. Note that there is a limitation to this technique: the program must be loaded into either resident memory (without use of RELEASE on the LIBRARY statement) or present memory for it to work. This is because the technique relies on the library's global variables remaining active even after function calls to it have been completed.

MAIN PROGRAM
00005 LIBRARY "howto2nl" : FNDOCEST,FNWRITETIME
00010 PRINT "Enter estimated number of pages:"
00020 INPUT PAGEEST
00030 LET FNDOCEST(PAGEEST)
00040 IF FNWRITETIME>8 THEN PRINT "Total days: ";FNWRITETIME/8
LIBRARY
02000 DEF LIBRARY FNDOCEST(&PAGEEST)
02010  LET WRITETIME=(PAGEEST*2)*1.15 ! Two hours per page, plus 15% for index
02020  PRINT "Documentation estimate is:";WRITETIME;"hours"
02030 FNEND
03000 DEF LIBRARY FNWRITETIME=WRITETIME
Example 4

Existing program queries or modifies function variable from outside function
In the following example, line 00120 of the main program logic modifies the value of TOTTIME, which is established by the FNDOCEST function. It is important that this modified value be communicated back to the function, because line 02030 of the function uses it for subsequent calls. Note also that lines 00100 and 00130 of the main program logic also query (without modifying) the value of TOTTIME.

MAIN PROGRAM
00010 PRINT "Enter estimated number of pages for chapter 1:"
00020 INPUT PAGEEST
00030 LET FNDOCEST(PAGEEST)
00040 PRINT "Enter estimated number of pages for chapter 2:"
00050 INPUT PAGEEST
00060 PRINT "Is subject matter highly technical? (Y/N)"
00070 INPUT TECHLEVEL$
00080 LET FNDOCEST(PAGEEST)
00090 IF UPRC$(TECHLEVEL$)="Y" THEN
00100  LET SURPLUS=TOTTIME*.2
00110  PRINT "Surplus time for technical matter: ";SURPLUS;"hours"
00120  LET TOTTIME+=SURPLUS
00130  PRINT "Total time is ";TOTTIME;"hours"
00140 END IF
LIBRARY
02000 DEF FNDOCEST(&PAGEEST)
02010  LET WRITETIME=(PAGEEST*2)*1.15 ! Two hours per page,plus 15% for index
02020  PRINT "Documentation estimate is: ";WRITETIME;"hours"
02030  PRINT "Accumulated total is: ";TOTTIME+=WRITETIME;"hours"
02040 FNEND

As noted for the previous example in this section, programming practices such as this are not recommended for new development that is to utilize the Library Facility. These examples are supplied to help you quickly modify existing programs so they can utilize the benefits of libraries.

The next two programs (main and library) show how the original program was changed to work with libraries.

MAIN PROGRAM
00005 LIBRARY "HOWTO3NL" : FNDOCEST,FNADD TOTTIME
00010 PRINT "Enter estimated number of pages for chapter 1:"
00020 INPUT PAGEEST
00030 LET FNDOCEST(PAGEEST)
00040 PRINT "Enter estimated number of pages for chapter 2:"
00050 INPUT PAGEEST
00060 PRINT "Is subject matter highly technical? (Y/N)"
00070 INPUT TECHLEVEL$
00080 LET FNDOCEST(PAGEEST)
00090 IF UPRC$(TECHLEVEL$)="Y" THEN
00100  LET SURPLUS=FNADD TOTTIME(0)*.2
00110  PRINT "Surplus time for technical matter: ";SURPLUS;"hours"
00130  PRINT "Total time is ";FNADD TOTTIME(SURPLUS);"hours"
00140 END IF
LIBRARY PROGRAM
02000 DEF LIBRARY FNDOCEST(&PAGEEST)
02010  LET WRITETIME=(PAGEEST*2)*1.15 ! Two hours per page,plus 15% for index
02020  PRINT "Documentation estimate is: ";WRITETIME;"hours"
02030  PRINT "Accumulated total is: ";TOTTIME+=WRITETIME;"hours"
02040 FNEND
03000 DEF LIBRARY
FNADD TOTTIME(ADDTOTTIME)=TOTTIME+=ADDTOTTIME

Once the required steps of separating the two programs, adding the necessary LIBRARY statement to the main program and adding the LIBRARY keyword to the DEF statement in the library program were completed for the above code, the following steps were conducted to enable the main program and function to communicate the value of TOTTIME. Note that there is a limitation to the technique shown: the library program must be loaded into either resident memory (without use of RELEASE on the LIBRARY statement) or present memory for it to work. This is because it relies on the library's global variables remaining active even after function calls to it have been completed.

1.) The FNADD TOTTIME function was added to the library program (line 03000). This function takes a variable (representing the amount to add to TOTTIME) that is passed by the main program. It adds the passed variable to TOTTIME, and also assigns the new value of TOTTIME to the function variable FNADD TOTTIME.
2.) The FNADD TOTTIME function name was added to the LIBRARY statement on line 00005 of the main program.
3.) Line 00120 of the main program was removed, and line 00130 was modified to call the FNADD TOTTIME library function instead of modifying TOTTIME directly. The value of SURPLUS is passed to FNADD TOTTIME; FNADD TOTTIME takes over the job of modifying the value of TOTTIME and making sure that both the main program and the library program know its new value.
4.) Line 00100 of the main program was changed to call the FNADD TOTTIME function as well. Since this line only needs to query the value of TOTTIME, it passes a value of 0 as the amount to add to TOTTIME.
Example 5

Turning an existing program into a user-invokable library function
Business Rules Library Facility makes it very easy to turn an entire program into a library function that a user can invoke at will from within another program. For example, consider a standard application that includes both a client maintenance (MNTCUST) program and an order entry program (ORDERS). You would like to give users the ability to invoke the client maintenance program from within the order entry program whenever they press F4. The steps required to do this are as follows:

1.) Modify MNTCUST by placing the entire original program into a user-defined library function and adding a few lines that cause the program to call itself as a library function whenever it is executed as the main program.
a.) Move any user-defined functions that exist within the main body of the program to the end of the program (or to a separate library).
b.) Add lines such as the following to the top of the program. NOTE that the (program name) in line 00030 represents the name of the program (such as a main menu) from which you currently normally invoke the client maintenance program.
00010 LIBRARY "MNTCUST" : FNMNTCUST
00020 LET FNMNTCUST
00030 CHAIN (program name)
00040 DEF LIBRARY FNMNTCUST
c.) Add the following line to the end of the main body of the program (prior to any user-defined function definitions):
80000 FNEND
2.) Modify ORDERS as follows:
a.) Change the screen to include a label that identifies the operation of the F4 key.
b.) Change the program to check for pressing of the F4 key.
c.) Change the program to execute the following whenever F4 is pressed. Note that the LIBRARY statement in line 50000 utilizes the "RELEASE" keyword: this causes the MNTCUST library to be loaded into memory on an as-needed basis only. Thus the only time that the on-the-fly client maintenance feature uses system resources is when the user actually requests the capability by pressing F4.
50000 LIBRARY RELEASE, "MNTCUST" :FNMNTCUST
50010 LET FNMNTCUST
Example 6

Tips for moving FNSNAP! functions into separate libraries for users of FNSNAP! programming tools, modifying existing programs to use libraries will involve a combination of the techniques demonstrated above. Every developers programs are different, so this section cannot give you a beginning-to-end list of steps to complete to accomplish the task, but the following are some steps you can start with:

1.) Place the FNSNAP! functions into their own program. (This example uses MAIN\\FNSNAP as the path and location of the new program.)
2.) Modify the DEF line for each of the functions in FNSNAP to utilize the LIBRARY keyword. For example:

Change this:

60150 DEF FNOK

To this:

60150 DEF LIBRARY FNOK
3.) Add the following FNFNSNAP INIT function to the FNSNAP program. This function sets all the global variables that are used by the FNSNAP functions (in the past, FNSNAP! users were instructed to add these variable settings to the start of their programs). FNFNSNAP INIT also executes a LIBRARY statement for the FNSNAP program. This LIBRARY statement establishes linkage for all the functions in the FNSNAP program that are called by other functions in the same program.
00121 DEF LIBRARY FNFNSNAP INIT
00122 LET DATFMT$="MM-DD-CCYY" !:LET FULLSCR=0 !:LET MAXSROWS=22 !:LET WINDEV=OWINDEV=69 !:LET MGA$="24,2,C 78," !:IF NOT SSAV THEN LET SSAV=101 !:!Common Variables required by FNSNAP! !:
00124 LIBRARY "MAIN\FNSNAP" : FNRELPART,FNSAVPART, FNPM, FNAUTO, FNOK, FNWIN,FNCLSWIN, FNZERO, FNTIMMILREG, FNSSAV,FNSAVSCR, FNSETBAD, FNPURGE, FNFLDSEL$
00130 FNEND !:
4.) Delete the separated functions from the main programs that are to use the FNSNAP library.
5.) Add the following program line to each of the main programs that are to use the FNSNAP library. This statement establishes linkage between the functions to be called and the program they are located in, and it calls the FNFNSNAP INIT function, which sets the library's global values:
00160 LIBRARY "MAIN\FNSNAP":FNFNSNAP INIT, FNSSAV, FNPOPWIN,FNPOPBAR, FNWINDEV, FNPOPWIN INIT,FNPOPBAR INIT, FNCO$, FNMGCLR, FNTOP,FNOK, FNSAVSCR, FNSCRMGR, FNSAVPART,FNRELPART, FNCLRPART, FNZERO, FNNULL$,FNTIMMILREG, FNDIALOG$, FNWIN, FNCLSWIN,FNNOKEY, FNPOPUP, FNPM, FNAUTO,FNPFKEYLINE !:LET FNFNSNAP INIT !:!

Error Processing

If an error is not trapped in a library function, the error is reported back to the calling program. At this time the following system variables are set:

LINE The line number of the calling program function call.
ERR The error number that occurred in the library function.
CNT The appropriate value as if the error occurred in the calling program.


If an error occurs while attempting to match parameters between a function call and the function definition, CNT is set to the number of parameters successfully matched.