We now have encapsulated procedures that are relatively easy to maintain. We've taken great care to develop our procedures so that we reuse as much code as possible instead of rewriting it. One thing we haven't focused on much yet is making the procedures as user-friendly as possible from the programmer perspective.
Let's look at our IsWorkday example. There are still a number of problems with this procedure. First, all it's really telling us is if the given date is a weekday, not necessarily a workday. Second, even though the DayOfWeek procedure is testing for a valid date, no error condition is available for the caller. If the caller is unsure about the validity of a date, it must do the testing itself.
Therefore, we're going to make some additional changes to IsWorkday. First, we're going to assume that we have a file available keyed by date that has a record present for every holiday. For a non-weekend date, we're going to check this file to see if it is a holiday.
Because we're using a file now, we're also going to extract the IsWorkday procedure from the source member containing DayOfWeek. If we didn't do this, every time we used procedure DayOfWeek on it's own, the system would go through the overhead of opening a data path for the holiday file.
Next, we're going to add another parameter to indicate to the calling program if the date passed was valid. We don't however want to force the calling program to always pass this second parameter. The procedure may often be used by a program that knows the date is valid. Therefore, we're going to make this parameter optional.
Finally, we're going to use the CONST keyword to indicate that the date parameter will not be modified by the procedure.
First, lets look at the new procedure:
Let's now look at the individual changes.
By adding the CONST keyword to the date parameter, we are telling the compiler and users of the procedure that the date field passed into the procedure will not be changed. We use the keyword for two reasons. First, it is a form of documentation for the users of the procedure that they can be assured that the parameter will not be changed.
More importantly, without the constant keyword users of the procedure will not be allowed to pass constants. For example, look at the following procedure call:
This will not compile unless the parameters is coded with the CONST keyword.
Note, when we are chaining to the HOLIDAY file we need to convert the date if it was passed as YYMMDD. Because it is a constant, we can not change the field directly. Instead, we set up a temporary work field.
Once a parameter is declared as a constant, it may not be used as anything other than a constant. This means we needed to declare the date in DayOfWeek as a constant also.
As a general rule of thumb, if a procedure uses a parameter as input only and will not modify it's contents, it should be coded as a constant. If a parameter will be changed for purposes of passing information back to the calling procedure (such as a return code), do not code it as a constant.
Using the OPTIONS(*NOPASS) keyword on a parameter indicates that the parameter is optional when the procedure is called. Optional parameters are often used for fields that we can supply a default value for if a parameter is not passed. Return codes or error codes are also often coded as optional.
By coding our return code parameter as optional, either of the following two procedure calls are valid.
This way we can allow the users of the procedure to decide if they want the return code or not. With a single statement, a user can now validate a date field and check if it is a workday!
Because parameters are positional, once you specify *NOPASS on a parameter, all parameters after that must be also be coded with *NOPASS. When the procedure is called, if an optional parameter is omitted, all parameters after that must also be omitted.
A procedure can check if an optional parameter was passed by using the %PARMS built in function. %PARMS will be set to the number of parameters passed. Note that we are checking for %PARMS > 1 rather than %PARMS = 2. This is done to simplify maintenance if at a later time we add more parameters.
Note that our IsWorkday procedure is not actually calculating the return code. Instead, this is left to the DayOfWeek procedure where the date testing occurs. Although it's not shown here, we also changed DayOfWeek to accept an optional return code parameter. If a valid date is passed, return code is set to 0, otherwise it is set to 1.
It also a good idea to standardize return codes. I normally use a 3-digit number, with zero indicating no errors, and the higher the number indicating a more sever error.
Note that on one of the procedure calls to DayOfWeek we are including a return code which will be set to indicate the validity of the date field. The return code we are passing was defined in the procedures D-specs, rather that field defined on the procedure interface.
Towards the end of the procedure we are checking if a return code was requested by the caller. If it is, we return the value that was set by the DayOfWeek procedure. You MUST do this check on optional return values. If we tried to set a value on an optional field that WASN'T passed, we would get a run time error. We don't need to do anything special to pass back the return code to the calling procedure. Remember, parameters are passed by address. When we change the value of the parameter in the procedure, we are actually modifying the memory's contents in the calling procedure.
Send mail to email@example.com
with questions or comments about this web site.
Last Modified: September 07, 2000