In my never-ending attempt to move RPG IV programmers toward using subprocedures, I found that a basic introduction to subprocedure architecture was missing. There are several specific examples out there of using APIs or RPG-only routines, but there really isn't a good subprocedure orientation.
Subprocedures are the RPG IV implementation of ILE procedures. Most high-level languages—such as C, COBOL, Visual Basic, and Java—have some sort of subroutine feature. Even RPG III includes "subroutines" (as does RPG IV). But RPG IV subprocedures are more like the features of those other languages than subroutines.
Subprocedures are isolated routines that are similar to standalone programs. They allow you to declare variables and write code that is independent of the source member in which it is contained. For example, if you have a traditional RPG program with mainline calculations, you probably have several work fields declared. Often those work field names are vague at best; names such as WRK1, WRK#, or @WORK are some heart-breaking examples.
But with a subprocedure, all declared fields are unique. For example, when program A is created, its fields are separate and distinct from those of program B. Likewise, a subprocedure's fields are separate and distinct from the rest of the source member. This means that you can declare a work field with a distinctive name within a subprocedure. So rather than declaring an ambiguous field named WRK#, you could declare a field name, such as AcctBalance (or ACTBAL if you prefer shorter names).
Fields declared in subprocedures are called "local variables." The content exists while the subprocedure is running and is destroyed when the subprocedure ends. So when the subprocedure is called a second time, the fields are reinitialized. This is similar to calling a program, setting on LR in that program, returning to its caller, and then calling the same program again. But with a subprocedure, you don't set LR on or off.
Subprocedures accept parameters just like programs accept parameters. But unlike a program-to-program CALL operation in RPG, when a subprocedure is called, you should use prototyping. When a call to the subprocedure is performed, parameters are passed to the subprocedure in a way that is syntactically similar to the way CL program-to-program calls are specified. That is, you don't use PLISTs (parameter lists); you simply put the data or the variable containing the data on the call statement itself. A simple example might be something like the following:
callp GetBalance( custNo : actBal );
This call to the subprocedure named GetBalance passes two parameters. From the name, we can infer that the account balance for the given customer number is being retrieved. Note that this example is in free-format RPG IV, but the hybrid syntax (using the fixed-format columns) has the same syntax except for the terminating semicolon, as follows:
C callp GetBalance( custNo : actBal)
Unlike program parameters, subprocedure parameters can include extended attributes that allow you to control whether or not they can be modified, whether the value passed can be a literal or a field, and several other options.
Prototyping: What Is It?
I am often asked what the prototype is used for. Sometimes, I think prototyping was added to RPG IV just to make the compiler more anal-retentive. The fact is that prototypes, in the context of subprocedures, are simply a declaration of the parameter list used by a subprocedure. Normally, a prototype is a direct copy of the subprocedure's parameter list.
The compiler uses the prototype source code to validate that the parameter values specified when the procedure is called match what the subprocedure is expecting. Of course, you can cheat and change the parameter definitions for a prototype (a prototype is nothing more than source code after all), hence lying to the compiler and causing a runtime error.
Prototypes are usually stored in a source member and then /COPYed into the source member where the subprocedure is defined, as well as any other source member that calls the subprocedure. This means the source code of the prototype can be /COPYed into many source members; it should, therefore, never be hard-coded in the source member where the subprocedure is also defined.
When you see a subprocedure in an expression, it is often used as follows:
eval balance = GetBalance( custNo );
The field named BALANCE is assigned the return value from the GetBalance() subprocedure. The return value is sent back to the calling RPG expression by the subprocedure using the RETURN operation code. Whatever value is specified in Factor 2 of the RETURN operation code is sent back to the caller and inserted into the expression in place of the call to the subprocedure. This gives you the ability to avoid modifying parameters when a simple return value is generated by the subprocedure.
A return value is not required for subprocedures. In the C language, a return value is often used as an "OK" code for the successful execution of the subprocedure; that is, if no return value is desired, one is implemented anyway to provide the user of the subprocedure a way to determine whether or not the subprocedure ran successfully.
To define the return value, specify its attributes, just as you would with a parameter, but code it on the first line of the procedure interface (i.e., parameter list), as follows:
A return value is entirely optional (as are parameters). To define a subprocedure without a return value, simply omit the return value definition, as follows:
Subprocedures can be an effective way to write code that can be used and reused over and over again. It also allows others to take advantage of the code you have written. Lastly, it gives us the ability to write libraries of routines that we can make publicly available for use by any RPG or CL application. Bob Cozzi is a programmer/consultant, writer/author, and software developer of the RPG xTools, a popular add-on subprocedure library for RPG IV. His book The Modern RPG Language has been the most widely used RPG programming book for nearly two decades. He, along with others, speaks at and runs the highly-popular RPG World conference for RPG programmers.