The main things to understand when trying to learn Modular Programming is:
-> How RPG Programs communicate with one another by passing data values as Parameter Arguments.
-> How to code Procedures, Procedure Interfaces and Prototypes to code your own Functions.
-> How to call API’s from within Programs
-> How to share data among Programs through Data areas
Why Modular Programming?
Imagine having to write a 1000 line program in one go and then test and debug it again in one go. Also consider having to maintain the same program to accommodate changes in requirements. Now compare this effort against that required to write/maintain small independent units of code that does the same. The advantages are plenty – Independent modules can be re-used for other programs that require the same processing logic,Testing, Maintenance and Debugging becomes much simpler, Code changes to the modules cause lesser unexpected side effects.
The main Op code to be used in the Modular approach is CALLP – Call a Prototyped Procedure or Program. Before CALLP can be used to call a Program, the call interface must be defined to the Program.
A call interface must contain the following information:
==> The name of the program to call
==> The number of parameters to pass and their data attributes
To define this interface, a structure called as ‘Prototype’ is used.
A Prototype must be used in the Definition specification of the calling program.
A prototype definition must include the below:
1) The Prototype definition itself
2) The description of the parameters to be passed between the caller and the callee.
As can be seen in the code below, inside the EXTPGM parentheses is the name of the *PGM program object which can be specified as a literal or can be a variable containing the Program name.
The Program being called must have a Procedure interface and a Procedure Prototype that must match the prototype in the calling program.
A complete Program example is given below. Please note that this is not a very useful piece of code. The idea is just to write a simple enough program through which the syntax and associated details of making a prototyped call to a program can be understood.
So what I have come up is a program which makes a prototyped call to another program which accepts as parameters two numbers and displays the sum on screen.
Calling Program:
DDSPMOD PR EXTPGM('DSPMOD') --> Prototype Header
DNUM1 3 0 CONST --> Parameter Definition
DNUM2 3 0 CONST --> Parameter Definition
/Free
CallP Dspmod(4:2); --> Prototyped call to the program DSPMOD
*Inlr = *On;
/End-Free
Below is the DSPMOD Program which is compiled and exists as a *PGM object.
DDspFun PR Extpgm('DSPMOD')
D 3 0
D 3 0
DDspFun PI
DNum1 3 0
DNum2 3 0
DRes S 3 0
/Free
Res = Num1 + Num2;
Dsply Res;
Return;
/End-Free
All Parameters are passed by Reference and not by value by RPGIV. How to pass parameters by Value will be discussed at a later stage.
What the above sentence in red (yes, its that important) means is that whenever you pass arguments to a function, you are passing the actual address of the variable. Not just the values. So if the called program modifies the value of the parameter passed, the calling program also will have the new value of the variable.
An example to illustrate this below.
Calling Program:
DChangeVar PR Extpgm('CHANGER')
DNum 3 0
DOriginal S 3 0 INZ(5)
/Free
Dsply Original; //Original value
CallP ChangeVar(Original); //Call the program to change the value of the Variable
Dsply Original; //Display Variable value again
*Inlr = *On;
/End-Free
Called Program:
DChanger PR Extpgm('Changer')
DNumToBeChanged 3 0
DChanger PI
DNumToBeChanged 3 0
/Free
NumToBeChanged = 100;
Return;
/End-Free
Another important point to be noted is that the program name inside the EXTPGM keyword in the Prototype header should be in Capitals. Otherwise the program compiles fine but you end up with a run time error.
Another very important point to consider is the behavior of programs being called if they are called multiple times by the same program.
A called program returns control back to the Calling Program when it encounters a RETURN Statement. Another way to return control is by setting INLR to ON.
There is a huge difference between the two and if the INLR is not set on, the behavior is very interesting. If a simple return is made without setting INLR to *ON, all resources remain as it is in the called program. That is if there are variables values being set, the values are retained in the next call. If there are files open, they are not closed. These effects might be wanted or unwanted based on Program logic.
The example below illustrates what happens if you return to a called program without setting on the last record indicator.
The requirements to call one RPG IV program from another is summarized below.
Calling Program:
- A Prototype of the program to be called.
- A CALLP opcode to execute the call.
Called Program:
- A Prototype definition to describe the parameters to be received.
- A Prototype Interface to receive the parameters.
- Return operation to return to the calling program.
Well wrap it up at this for the first part on Modular programming. Well discuss the remaining areas in Part 2 of this post.