The simplest way to use a procedure in ILE RPG is to code it directly in your program's source member. This is very similar to coding a subroutine (in fact, it is also very easy to convert a subroutine to procedure).
An internal procedure is always coded towards the end of the program, after any mainline code (including subroutines). The general program structure with an internal procedure is as follows:
Data defined in the mainline section of the code is global and may be used or updated by any of the procedures.
Data defined within the procedures is local and is only available to the procedure itself (using the import/export keywords on the D-specs may be used to implicitly share local variable however - we'll cover this later).
Defining a procedure
All procedures must be defined with a beginning and ending P-spec. A P-spec is new to RPG IV. The layout is very straightforward:
Like D-specs, the procedure name does not need to be left-justified. It may be indented for readability.
Position 24 must be coded with a "B" to indicate the beginning of a procedure, and an "E" to indicate the end. The only keyword valid right now for a P-spec is export which may be coded on the beginning P-spec to indicate that the procedure may be used by other external programs (we'll cover more on this later).
In the following example, we're going to code an RPG procedure to determine if a given date is a workday or a weekend. The procedure is going to return a boolean value (true or false). We will therefore name the procedure "IsWorkday". The beginning and ending P-specs will look like this:
All code between the beginning and ending P-specs are part of the procedure.
Keep in mind that procedure name are not case-sensitive, and the space immediatly after the "P" is just for readability. We could have defined the exact same procedure as:
All procedures must be defined with a procedure interface. This is kind of like an *ENTRY PLIST for a called program but with more flexibility. The procedure interface is defined in D-specs, and in addition to defining the parameters passed into the procedure, it also defines the data type of one (and only one) return value.
The procedure interface for our IsWorkday procedure will look like this:
The "PI" in positions 24-25 of the first line indicates that we are defining a procedure interface for a procedure named "IsWorkday". The "N in position 40 means that this procedure will return an indicator-type value (boolean) after it executes. If it was returning an string or number, a length would also be specified.
The second line indicates that the procedure will require one parameter - a date-type field - when it is called. The incoming parameter will be placed in a field named @DATE. Again, it is not necessary to specify a length for a date field. If there were numeric or alpha fields passed as parameters, a length would be required.
We can additional parameters by specifying more D-specs. There are also quite a few keywords available to further define our procedure interface and it's parameters. We'll cover these a little later.
Defining Local Variables
For this particular procedure, we will need to defined several work fields. Instead of defining these variable in the mainline program, we can define them as local variable by declaring them within the procedure. We will then not need to worry about naming conflict either with the mainline code or with other procedures.
First, we've defined a field call @BaseDate that we know to be a Sunday. We've also defined two other numeric fields that we will use for intermediate calculations, and the indicator-type field that we will use to return the result of the procedure.
Because of the built-in date support, the actual code to determine if a date is a weekend or weekday is pretty easy:
First, we use the SUBDUR operation code to determine the number of days between our base date (a Sunday) and the date passed to the subroutine. The result is stored in work field @Days.
Next, we use the built-in-function %REM to divide @Days by 7 and store the remainder in another work field called @DayOfWeek. Because we know that @BaseDate is a Sunday, if @Days in an exact multiple of 7, @Date is also a Sunday. If there is a remainder of 1, @Date is a Monday. A remainder of 6 means @Date is a Saturday.
The next IF statement assigns a value to @WorkDay based on the value of @DayOfWeek. If @DayOfWeek is a 0 (Sunday) or 6 (Saturday), @WorkDay is set to *off (false). Otherwise @WorkDay is set to *on (true).
The last statement ends the procedure and sets @WorkDay as the return value. Because we defined the procedure as returning an indicator data-type on the procedure interface, we must specifiy a field defined as an indicator on the return statement. If we tried to return a different data type than what we coded on the procedure interface, we would get an compiler error.
The Whole Procedure
Putting the pieces together and adding some comments, the procedure now looks like this:
Send mail to firstname.lastname@example.org
with questions or comments about this web site.
Last Modified: August 22, 2000