In this section: |
You can call one Maintain procedure from another with the CALL command. (Maintain procedure here means any procedure of Maintain language commands.) CALL simplifies the process of modularizing an application; software designed as a group of related modules tends to be easier to debug, easier to maintain, and lends itself to being reused by other applications—all of which increase your productivity.
CALL also makes it easy to partition an application, deploying each type of logic on the platform on which it will run most effectively.
The following diagram illustrates how to describe the relationship between called and calling procedures. It describes a sequence of five procedures from the perspective of the middle procedure, C FOCEXEC. (Note that a root procedure is also called the starting procedure.)
Consider the EMPUPDAT procedure:
MAINTAIN FILE Employee FOR ALL NEXT Emp_ID INTO EmpStack; . . . CALL NewClass; . . . END
This calls the NEWCLASS procedure:
MAINTAIN . . . END
In this example, EMPUPDAT is the parent procedure and NEWCLASS is the child procedure. When the child procedure—and any procedures that it, in turn, has invoked—has finished running, control returns to the parent.
All user variables (both stacks and simple, or scalar, variables) are local to a procedure, not global to the application. In other words, to protect them from unintended changes in other parts of an application, you cannot directly refer to a variable outside of the procedure in which it is found (with the exception of the FocError, FocErrorRow, FocFetch, and FocCurrent transaction variables). However, you can access a variable's data in other procedures, simply by passing it as an argument from one procedure to another.
To pass variables as arguments, you only need to name them in the CALL command, and then again in the corresponding MAINTAIN command. Some variable attributes must match in the CALL and MAINTAIN commands:
Other attributes need not match:
Once you have passed a variable to a child procedure, you must define it in that procedure. How you define it depends upon the type of variable:
COMPUTE Counter/A20; EmpStack.FullName/A15;
INFER Emp_ID Pay_Date INTO EmpStack;
The INFER command declares data source fields and the stack with which they are associated. You can specify one field for each segment you want in the stack or simply one field each from the anchor and target segments of a path you want in the stack.
While INFER reestablishes the stack's definition, it does not retrieve any records from the data source.
Once a variable has been defined in the child procedure, its data becomes available. If you refer to stack cells that were not assigned values in the parent procedure, they are assigned default values (such as spaces or zeros) in the child procedure, and Maintain displays a message warning that they have not been explicitly assigned any values.
When the child procedure returns control back to the parent procedure, the values of stacks and simple variables specified as INTO variables are passed back to the parent. The values of stacks and simple variables specified only as FROM variables are not passed back.
For example, this procedure,
MAINTAIN FILE Employee FOR ALL NEXT Emp_ID INTO EmpStack; . . . CALL NewClass FROM EmpStack CourseStack INTO CourseStack; . . . END
calls the NEWCLASS procedure:
MAINTAIN FROM StudentStack CourseStack INTO CourseStack . . . END
EmpStack and CourseStack in the parent procedure correspond to StudentStack and CourseStack in the child procedure.
If a child procedure accesses a data source, whether retrieving or writing records, you must specify the data source in the MAINTAIN command. This is done the same way as for a stand-alone procedure. For example:
MAINTAIN FILES Employee AND EducFile FROM StuStk INTO CoursStk . . . END
Each Maintain procedure tracks its own position in the data source. When you first call a procedure, Maintain positions you at the beginning of each segment in each data source accessed within that procedure; after navigating through a data source, you can reposition to the beginning of a segment by issuing the REPOSITION command. Each procedure's data source positions are independent of the positions established in other procedures.
When a child procedure returns control to its parent, by default it clears its data source positions. You can specify that it retain its positions for future calls by using the KEEP option, as described in the Optimizing Performance: Data Continuity and Memory Management.
By default, when you terminate a child procedure, Maintain clears its data from memory to save space. You can optimize your application's performance by specifying, each time you terminate a child procedure, how you want Maintain to handle the procedure's data. You have two options, based on how often you will call a given procedure over the course of an application:
This option provides data continuity; the procedure's data carries over from the end of one invocation to the beginning of the next. That is, the next time you call the procedure, its variables and data source position pointers start out with the same values that they held when the procedure was last terminated. You can use these values or, if you wish, re-initialize them using the DECLARE (or COMPUTE) and REPOSITION commands.
Variables passed by the parent procedure are not affected by data continuity, since the child procedure receives them directly from the parent procedure at the beginning of each call.
The KEEP option does not issue an implied COMMIT command at the end of a child procedure. When a child procedure with an open logical transaction returns to its parent procedure and specifies KEEP, the transaction continues into the parent.
This option does not provide data continuity; all of the procedure's variables and data source position pointers are automatically initialized at the beginning of each procedure.
The RESET option issues an implied COMMIT command at the end of a child procedure. When a child procedure with an open logical transaction returns to its parent procedure using RESET, the transaction is closed at the end of the child procedure.
For more information about transactions spanning procedures, see Designing Transactions That Span Procedures.
You can specify how a procedure will handle its data in memory by terminating it with the GOTO END command qualified with the appropriate memory-management phrase. The syntax is
GOTO END [KEEP|RESET];
where:
Terminates the procedure, but keeps its data—the values of its variables and data source position pointers—in memory. It remains in memory through the next invocation, or (if it is not called again) until the application terminates. The procedure does not issue an implied COMMIT command to close an open logical transaction.
Terminates the procedure, clears its data from memory, and issues an implied COMMIT command to close an open logical transaction. This is the default.
You can use both options in the same procedure. For example, when you are ready to end a child procedure, you could evaluate what logic the procedure will need to perform when it is next called and then branch accordingly either to keep data in memory, saving time and providing data continuity, or to clear data from memory to conserve space.
Information Builders |