Meaningful Indicator Names

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 ArrayStandalone 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.

Indicators/td>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.