This first example of code shows the indicator array being referenced by an array using the overlay keyword. The indicator array from 50-59 is used for display file functions so that in the code, there is no need to guess which indicator (50 or 51, or ??) turns on the subfile display--the indicator SFLDISPLAY is self documenting.
|Indicator Array||Standalone indicators|
d indPtr s * inz( %addr(*in) ) * define named indicators d indicators ds 99 based( indPtr ) d ScreenChange n overlay( indicators : 22 ) d SflControl n overlay( indicators : 50 ) d SflDisplay n overlay( indicators : 51 ) d SflInitialize n overlay( indicators : 52 ) d SflClear n overlay( indicators : 53 ) d SflEnd n overlay( indicators : 54 ) d SflDelete n overlay( indicators : 55 ) d SflNxtChange n overlay( indicators : 58 ) d SflMSGQdisplay... d n overlay( indicators : 59 ) sflControl = *ON ; IF sflrcn > 0 ; sflDisplay = *ON ; ENDIF ; WRITE SC032001 ; EXFMT SC0320C1 ;
FGPORTABB IF E K DISK rename(GPORTA:INVOICES) d NoMoreInvoices S n inz(*OFF) d dtaPtr S * inz(%addr(noMoreInvoices)) d EndOfFile S n based( dtaPtr ) D invcnt S 7 0 /free SETLL (invdtz:invnoz) GPORTABB; DOU NoMoreInvoices; READ INVOICES; NoMoreInvoices = %eof(GPORTABB); IF not EndOfFile; invCnt = InvCnt + 1; ENDIF; ENDDO; *INLR = *ON; RETURN; /end-free
Individual named indicators can be used to describe conditions as well. In the next example, the same indicator (pointer location) can be made to represent different conditions. The indicator variableS ENDOFFILE and NOMOREINVOICES may be used to represent different aspects of the same condition. This allows the code to be self documenting. This technique reminds me somewhat of COBOL where 77 level items in working storage were desrcibed as conditions. In this code example, ENDOFFILE is actually a condition relative to NOMOREINVOICES.
Evolving from RPG II, where conditioning indicators were the sole method of decision logic, indicators moved from the line level to the op code level in RPG III. Shortly thereafter, programmer design tried to move beyond indicators and there use declined in RPG/400. But with the advent of program-defined Boolean variables, indicators show some signs of making a return in RPG. Though it is not the necessity it once was the data definition (D) specs provide support for Boolean variables. The following describes named indicators, which may be used in the same manner as the *IN indicators.
0073.00 D ReturnRequested... 0074.00 D S n 0075.00 D ScreenChanged... 0076.00 D S n 0077.00 D RecordLocked S n 0078.00 D ErrorFound S n
In free-format code the named indicators can be used to construct logic loops, or decision statements in a fashion that mimics English language syntax, making the code easier to interpret. Downstream from this code you could perform an operation if the screen changed. The syntax would be simple and to the point. IF ScreenChanged, is fairly self-documenting and has more meaning to someone trying to maintain the code than IF *IN22 = *ON.
0094.00 DOU ReturnRequested 0095.00 IF not ReturnRequested 0096.00 ScreenChanged = *OFF 0097.00 EXFMT RATER102 0098.00 ScreenChanged = *IN22 0099.00 EXSR @SaveCursor 0100.00 SELECT 0101.00 WHEN KeyPressed = F8 0102.00 ReturnRequested = *ON 0103.00 EXSR @ProcessEntry 0104.00 WHEN KeyPressed = F12 0105.00 ReturnRequested = *ON 0106.00 ENDSL 0107.00 ENDIF 0108.00 ENDDO
To appreciate how program code can benefit from judicious use of named indicators, examine the sample below. The code (Fig. 1) below is functional and will perform in predictable fashion. However, it is cryptic, and could require a programmer to search the source to determine how and why the indicator *IN11 came to be set on. Modifying the code, a programmer would certainly want to know why *IN12 needs to be on before updating a record. The code can be made more intuitive with the use of named indicators.
0147.00 EXSR @CheckData 0148.00 IF *IN11 0149.00 *IN91 = *OFF 0150.00 ELSE 0151.00 IF z$mode <> 'ADD' 0152.00 EXSR @GetRateRecord 0153.00 ENDIF 0154.00 IF *IN12 = *ON 0155.00 EXSR @MoveToFile 0156.00 UPDATE DHRTRP 0157.00 *IN32 = *ON 0158.00 ENDIF Fig. 1
0147.00 EXSR @CheckData 0148.00 IF ErrorFound 0149.00 ReturnRequested = *OFF 0150.00 ELSE 0151.00 IF z$mode <> 'ADD' 0152.00 EXSR @GetRateRecord 0153.00 ENDIF 0154.00 IF RecordLocked 0155.00 EXSR @MoveToFile 0156.00 UPDATE DHRTRP 0157.00 RateAdded = *ON 0158.00 ENDIF Fig. 2
Since named indicator variables are indicators, they may be tested on IF statements without a comparison to a value, but rather stated as a condition, (IF/IF NOT). The following code demonstrates the how a Boolean variable might be used to present code that is more legible and more explicit than the example in Fig. 1. Though not perfect, the revised code using named indicators, is far easier to interpret. The statement IF ErrorFound in Fig. 2 is definitive, if generic. With the use of named indicators, the statements can be made as explicit as necessary to describe the error condition. Notice the IF RecordLocked statement. It is easily apparent that a record may be updated if the record if a lock has been granted. Downstream, testing whether a rate was added on the file is a simple test; IF RateAdded. Named indicators make for simpler, more maintainable code.
0044.00 D CustomerRateNotFound... 0045.00 D S 1n 0046.00 D OrderRateNotFound... 0047.00 D S 1n 0143.00 IF CustomerRateNotFound AND OrderRateNotFound 0144.00 CHAIN (i_opcm : k_swcat : k_swcode) SWCODEP 0145.00 IF not %found(SWCODEP) 0146.00 CHAIN (k_swcm : k_swcat : k_swcode) SWCODEP 0147.00 ENDIF 0148.00 mi_rate = swnum1 0149.00 mi_basis = %trim(swchr1) 0150.00 ENDIF 0151.00 i_rate = mi_rate 0152.00 i_basis= mi_basis 0153.00 i_miles= milesbilled 0154.00 ENDIF Fig. 3
The example, Fig. 3 illustrates how the use of named indicators for specific conditions can prove useful in interpreting code. The code snippet is attempting to retrieve a rate and rate basis, because, no customer rate was found and no order rate was found. It brings a degree of clarity to the decision that isnít available with the use of standard indicators. There is no technical superiority to using named indicators instead of standard indicators, in either case it distills down to a true or false test. However, the use of the named indicators can remove an amount of ambiguity from the code. And, that is a good thing.