Persistent procedures
- Last Updated: September 12, 2023
- 3 minute read
- OpenEdge
- Version 13.0
- Documentation
Why use persistent procedures?
As you have seen, you can run one procedure from another. When you do this, you can
pass INPUT parameters that are used by the procedure you run. When
that procedure gets to the end of its ABL code, it terminates and returns any
OUTPUT parameters to the caller. This works the same for both
external procedures (independent procedure source files) and for the internal
procedures inside them.
These procedures form a call stack. On top of the stack is the main procedure you run from the editor or from the OpenEdge startup command line. Below this is another procedure the main procedure runs, which in turn can run another procedure that is added to the stack, and so on. As each procedure terminates, it returns control to the procedure above it and is removed from the stack. All the resources it uses are freed up, and the procedure effectively disappears from the session unless it is run again. This figure provides a rough sketch of how the procedure call stack can look.
|
What does this really mean? All three of these procedures have been instantiated and are currently in the session’s memory. What is actually in memory is the r-code for the procedure, which the interpreter understands, whether this was a .r file you previously compiled and saved or whether the ABL Virtual Machine (AVM) has to compile the procedure on the fly at runtime from its source code.
It also means that all the elements that each procedure defines are currently in scope. Any variables, buffers, and other procedure objects have been instantiated along with the executable r-code. The AVM has allocated the memory and other resources needed to execute them.
It also means that control of the application flow is fairly rigid. The code in
MainProc.p cannot do anything at all while
SubProc.p is running. Likewise, the code in the main block
of SubProc.p cannot do anything at all while
InternalProc is running. The three procedures together form a
single thread that cannot be interrupted except to cancel the whole program
execution.
When InternalProc returns to the rest of
SubProc.p, any resources it defined, such as local
variables, are freed up. SubProc.p can go on with the rest of
its program logic. When SubProc.p returns to
MainProc.p, all the resources allocated to it, including
the in-memory copy of its executable code, are released and disappear. The code in
MainProc.p has no way of accessing anything in
SubProc.p except by receiving it back in the form of an
OUTPUT parameter, because while SubProc.p
is running, MainProc.p is completely blocked. When
SubProc.p returns control to
MainProc.p, it completely disappears.
The result is a very hierarchical application, both in its physical construction and in its user-visible execution. In a more modern application, designed to be distributed between client user interface sessions and separate server sessions that control the database, with the need to communicate with a variety of devices and other applications and to make the user much more in control of the application flow than before, this programming style is not sufficient. The procedures in your application must have greater flexibility in how they interact with each other, without depending on a rigid hierarchy of execution. Persistent procedures provide this flexibility.