During a lab session at the COMMON conference in Denver, we were surprised at the number of RPG IV programmers who seemed to have missed a significant event in the evolution of the language-namely, the death of the indicator. Or, to be more specific, the death of the *IN series of 99 numbered indicators. We consider this a great step forward in increasing the readability of RPG code. First came mixed case and field names longer than six characters, expressions and now, indicators with names.
The indicators days became numbered in V4R2, when new built-in functions (BIFs) and named indicators first made it possible to write nearly all RPG programs without using any of the *IN indicators. A few tenacious indicators hung on until V5R1 when the last of the operation codes requiring them were replaced with BIFs.
Let's begin with the V4R2 BIFs. These new functions can replace most resulting indicators-that is, the HI, LO and EQ resulting indicators from the right-hand side of the C spec:
- The %EOF function indicates an end of file condition on a sequential READ or a WRITE to a subfile.
- %FOUND indicates whether the requested record was found on CHAIN, DELETE, SETGT or SETLL operations. It can also be used with SCAN, CHECK, CHECKR and LOOKUP.
- %EQUAL is also set by the LOOKUP and SETLL operations when an exact match is found.
- Rounding out the new I/O BIFs is %OPEN. When using user-controlled file opens, this provides a more straightforward and efficient way of testing whether a file is open, rather than the common technique of testing for error conditions when an I/O operation fails.
Another new BIF, %ERROR, is used in conjunction with the E (error) operation code extender and replaces the Error resulting indicator. %ERROR is cleared whenever an operation that specifies the E extender is about to begin. If that operation results in an error condition, it is set on. The %Status function can be interrogated to determine the specific error that occurred.
Note that the E extender and %ERROR can only be used with operation codes that allow an Error indicator, including the TEST operation and standard I/O operations.
So, as the example below shows, we can now write all of this code without using indicators. (Note: The BIFs related to file I/O operations take an optional parameter of the file name. We recommend using the file name with these functions to make your intentions more obvious and your code more readable.)
C KeyValue Chain(E) KeyedFile
C If %Found(KeyedFile)
*** Process the record
C EndIf
C DoU %EOF(SeqFile)
C Read(E) SeqFile
C If Not %Error
*** Process next record
C EndIf
C EndDo
And, for all the V5R1 free-form fans out there:
/FREE
Chain(E) KeyValue KeyedFile;
If %Found(KeyedFile);
// Process the record
EndIf;
DOU %EOF(SeqFile);
Read(E) SeqFile;
If Not %Error;
// Process next record
EndIf;
EndDo;
That takes care of those pesky resulting indicators on I/O operations. Now, what about the indicators used in your externally described display and printer files? It would be nice if DDS supported Named indicators, but it doesn't. However, you can define Named indicators in your RPG program and map your DDS numbered indicators to those named ones. Let's examine an example.
FDispFile CF E WORKSTN IndDS(FileInds)
D FileInds DS
D Exit 3 3N
D Return 12 12N
D AllErrors 2 Overlay(FileInds:32)
D StartError N Overlay(FileInds:32)
D EndError N Overlay(FileInds:33)
C ExFmt MyScreen
C If Not Exit or Return
C Eval AllErrors = *Zeros
C If StartDate < Today
C Eval StartError = *On
C EndIf
C Eval EndError = EndDate < StartDate
C EndIf
Note the keyword IndDS-Indicator Data Structure -on the F spec. This tells the compiler to map the 99 indicators available for use in the display file to the data structure named "FileInds." An Indicator data structure has 99 bytes and the names are mapped by the relative position in the data structure (DS). Therefore, Exit is the name for Indicator 3 in our example. If, like us, you can't stand the thought of returning to using "from" and "to" notation for DS, consider the Overlay technique we show here for the two Error indicators (32 and 33). You can also group indicators together, as we did with AllErrors, so you can more easily turn them all on or off. Because they're indicators, of course, you can set them based on a conditional expression, as we show with EndError.
Be aware when using the INDDS approach that you must use the named indicators when controlling display file behavior. While *IN32 still exists in the RPG program and can therefore be set, doing so has no impact on the display attributes of DispFile. The only way to impact the display attributes conditioned with indicator 32 is to set on (or off) the StartError indicator.
Of course, the whole point of the exercise is to stop using the numbered indicators, so the limitation on using numbered and named indicators interchangeably isn't relevant in new programs. However, if you wanted to use named indicators in an existing program that uses numbered indicators extensively, it could be cumbersome (not to mention error-prone) to replace all uses of the numbered indicators in the display file. Pointers provide a mechanism to allow the interchangable use of numbers and names. In our July iSeries EXTRA column, we illustrated using pointers to make the *IN array to a data structure with named indicators.
If using pointers makes you nervous, you may want to consider one last alternative. You can use the fact that the *IN indicators can be referenced as an array and use constants to name the indicators. The following version of the previous display file example illustrates the technique.
FDispFile CF E WORKSTN
D Exit C 3
D Return C 12
D StartError C 32
D EndError C 33
C ExFmt MyScreen
C If Not *In(Exit) or *In(Return)
C Eval *In(StartError) = *Off
C Eval *In(EndError) = *Off
C If StartDate < Today
C Eval *In(StartError) = *On
C EndIf
C Eval *In(EndError) = EndDate < StartDate
C EndIf
While these V4R2 capabilities did much to remove the need for the *IN indicators, indicators were still essential in a few instances. The most significant of these was the LOOKUP op code. The results of the operation could be determined without resorting to the numbered indicators by using the %FOUND and %EQUAL BIFs. Indicators were still necessary, however, to specify the type of LOOKUP to perform. This changed when the new %LOOKUPxx BIFs were introduced in V5R1. Now you can specify the type of lookup to perform by selecting the appropriate BIF (%LOOKUPEQ, %LOOKUPGT, etc.). That noise you now hear is the sound of the final nails being pounded into the *IN coffin!
As you can see, there's no reason to continue to use numbered indicators. So let's let them rest in peace-they had a good run, but their time has come.