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, which is named C.
Note: A root procedure is also called the starting procedure.
If parent and child Maintain procedures reside on different servers, you identify the location of the child procedure in a deployment scenario in the Maintain Development Environment. At deployment time, the Maintain Development Environment automatically informs the parent procedure of the location of the child procedure by supplying the AT server phrase in the CALL command. Do not code the AT server phrase yourself unless the parent procedure is not part of your project.
If the parent procedure is not a native project component, code the AT server phrase yourself in the CALL command of the parent procedure (or use the Language Wizard to generate the CALL command) to identify the location of the child procedure.
Consider the EmpUpdat procedure:
MAINTAIN FILE Employee FOR ALL NEXT Emp_ID INTO EmpStack; . . . CALL NewClass; . . . END
This calls the NewClass procedure that is deployed on the EducServ WebFOCUS Server:
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 has invoked, have finished executing, control returns to the parent.
All user variables (both stacks and simple, or scalar, variables) are global to a function or procedure, but not global to the project. In other words, to protect them from unintended changes in other parts of a project, you cannot directly reference a variable outside of the procedure in which it is found (with the exception of the FocError transaction variable). However, you can access the variable 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, using the FROM phrase for input arguments and INTO phrase for output arguments. Some variable attributes must match in the CALL and MAINTAIN commands:
Other attributes need not match:
After you have passed a variable to a child procedure, you need to define it in that procedure. How you define it depends upon the type of variable:
DECLARE 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 definition of the stack, it does not retrieve any records from the data source.
After 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 a message is displayed 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 output arguments are passed back to the parent. The values of stacks and simple variables specified only as input arguments are not passed back.
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, the procedure below specifies the Employee and EducFile data sources:
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. The 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 Optimizing Performance: Data Continuity and Memory Management.
Modularizing source code into several procedures has many advantages. One benefit is that you can use multiple procedures, run using the CALL command, to share common source code among many developers, speeding up both development and maintenance time. For example, a generalized error message display procedure could be used by all WebFOCUS Maintain developers. After passing a message to the generalized procedure, the procedure would handle message display. The developers do not need to worry about how to display the message, and the error messages will always look consistent to end users.
Another advantage of modular design is that you can remove infrequently-run source code from a procedure and move it into its own procedure. This reduces the size of the original procedure, simplifying its logic, making maintenance easier, and using less memory if the new procedure is not called.
By default, when you terminate a child procedure, Maintain clears its data from memory to save space. You can optimize your application performance by specifying, each time you terminate a child procedure, how you want Maintain to handle the procedure data. You have two options, based on how often you will call a given procedure over the course of an application. If you will call the procedure:
This option provides data continuity. The procedure data carries over from the end of one invocation to the beginning of the next. 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 reinitialize them using the DECLARE (or COMPUTE) and REPOSITION commands.
Of course, 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.
KEEP affects transaction integrity in the following way. 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 variables and data source position pointers are automatically initialized at the beginning of each procedure.
RESET affects transaction integrity in the following way. 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 Ensuring Transaction Integrity in the Developing WebFOCUS Maintain Applications manual.
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];
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. RESET is the default value.
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 else to clear data from memory to conserve space.