• The Four Hundred
  • Subscribe
  • Media Kit
  • Contributors
  • About Us
  • Contact
Menu
  • The Four Hundred
  • Subscribe
  • Media Kit
  • Contributors
  • About Us
  • Contact
  • Four Ways to Avoid Problems Caused by Global Data

    December 10, 2008 Ted Holt

    Junior J. Programmer modifies an RPG program. His testing works properly. The user’s test works properly. The user approves the change, the modified program is installed, and everything is copasetic until a few months later when the program gets stuck in a loop. What happened, and why is Junior not entirely to blame?

    Here’s the code Junior added to the program:

    C     1             DO        5             X                 1 0
    C                   EXCEPT    PLINE
    C                   ENDDO
    

    What could go wrong with such simple code?

    It turns out that the subroutine that contains Junior’s code is also conditionally and indirectly executed from another part of the program.

    C                   IF        ACCOUNT <> *ZERO
    C     1             DO        8             X                 1 0
     ... calcs that indirectly execute Junior's code go here
    C                   ENDDO
    C                   ENDIF
    

    Since the condition was not directly over the execution of his subroutine (i.e., there were intervening subroutine calls), Junior did not realize that his testing had not covered all conditions. Nor did the user test the conditional logic. The first time ACCOUNT proved not equal to zero, the program went into an infinite loop.

    Junior’s mistake was in using the X variable to control the loop. His loop messed up the value of X in the outer loop. Since X was already defined as a one-digit packed variable, the compiler did not flag the duplicate declaration.

    This example is only one of many ways that a modification to a program can cause an error in another, correctly working section of code. I call these unintended consequences undesirable side effects, and to my way of thinking, the best way to debug undesirable side effects is not to put them into the code in the first place.

    In this case, the best way to avoid the infinite-loop problem would be through the use of a local variable, a variable that is known only within a section of code. Global data, on the other hand, is known throughout the entire program. Junior’s program went into a loop because X was a global variable.

    Ideally, your program should have no global variables, but that is not practical. Here are four ways that you can minimize the use of global variables. You can use these techniques at any current release. (V6R1 presents more opportunities to localize data, but that’s a subject for another day.)

    1. Use Subprocedures, Not Subroutines

    Unlike subroutines, subprocedures can have local data (i.e., variables, constants, and data structures). Local data follows the parameter list. In Junior’s case, had the program been written to use subprocedures, he would have added variable X as a local variable to the subprocedure that he modified.

    P OneSubProc      b                           
    D                 pi                          
    D**** parms                                   
     (... parms omitted ...)                      
    D*** local                                    
    D   X                            1p 0         
     (... code omitted ...)                       
    C     1             DO        5             X
    C                   EXCEPT    PLINE          
    C                   ENDDO                    
     (... code omitted ...)                      
    P                 e                          
    

    The subprocedure would have had a variable X, the calling routine would have had its own variable X, and the compiler would have kept them separate.

    2. Minimize the Main Declaration and Calculation Specs

    Ideally the D specs in the main body of an RPG IV program should be limited to parameter lists, compile-time tables and arrays, and program-wide data structures like the program status data structure. That is not always practical, but the closer you can adhere to this idea, the less chance you have of creating undesirable side effects.

    The main calculations should contain a call to one or more subprocedures. Here’s an example from a previous article of mine.

    H dftactgrp(*no) actgrp(Whatever)
                                               
    FXACTS     o    e             disk    usropn
                                                
    * ===== *ENTRY PLIST                       
    D SomePgm         pr                        
    D  inID                          5p 0       
    D  inName                       12a         
    D SomePgm         pi                        
    D  inID                          5p 0       
    D  inName                       12a         
                                                
    D/copy prototypes,assert                    
    D/copy qrpglesrc,psds                       
    D SomePgm_Main    pr                        
                                                
     /free                                      
         *inlr = *on;                           
         monitor;                               
            SomePgm_Main();
         on-error;                                        
            assert (*off: 'Unexpected error in program ' +
                          %trim(psdsProcName) +           
                          '. See job log for details.');  
         endmon;                                          
         return;                                          
         // ===========================                   
     /end-free                                            
    P SomePgm_Main    b                                   
     /free                                                
         open xacts;                                      
         ID = inID;                                       
         Name = inName;                                   
         write XactRec;                                   
         close xacts;                                     
     /end-free                                            
    P                 e
    

    The main program logic is in subprocedure SomePgm_Main, not in the main C specs. The only global data is in the parameter list and the files, but you can address that global data, too.

    3. Give Each File a Unique Prefix

    In releases before V6R1, all files must be declared globally, which means that all fields defined in files are global. Giving each file a unique prefix, and not using those prefixes on other data, decreases the chances of using a field or variable when it should not be accessed.

    I recommend prefixes of one or two letters followed by an underscore.

    FCustomer  if   e             disk    usropn prefix(c_)
    FMyReport  o    e             printer usropn prefix(p_)
    

    All fields from Customer begin with c_. All fields in the printer file begin with p_. If you don’t use these prefixes for anything else, there will be no confusion.

    4. Use a Special Prefix for Global Data

    I try to prefix global data with a small g. Any other convention is just as good. In the following example, the status parameter, from the program’s parameter list, and a tax rate variable are global data.

    D QAD2242R        pr                 
    D  gStatus                       1a  
    D QAD2242R        pr                 
    D  gStatus                       1a  
                                         
    D gTaxRate        s              9p 6
    

    It goes without saying that this technique is effective only if you do not use a little “g” to begin local data names within subprocedures.

    I don’t consider Junior completely at fault for introducing a bug into the program. While he should have used a better variable name than X, the original programmer could have written his source code with maintenance in mind.

    RELATED STORY

    Avoiding the Green Screen of Death in RPG Programs



                         Post this story to del.icio.us
                   Post this story to Digg
        Post this story to Slashdot

    Share this:

    • Reddit
    • Facebook
    • LinkedIn
    • Twitter
    • Email

    Tags:

    Sponsored by
    Rocket Software

    Unlock the full potential of your data with Rocket Software. Our scalable solutions deliver AI-driven insights, seamless integration, and advanced compliance tools to transform your business. Discover how you can simplify data management, boost efficiency, and drive informed decisions.

    Learn more today.

    Share this:

    • Reddit
    • Facebook
    • LinkedIn
    • Twitter
    • Email

    Sponsored Links

    VAULT400:  Never lose your data with VAULT400's online backup
    Computer Keyes:  KeyesOverlay rapidly converts standard *SCS printer files into PDF documents
    COMMON:  Join us at the 2009 annual meeting and expo, April 26-30, Reno, Nevada

    IT Jungle Store Top Book Picks

    Easy Steps to Internet Programming for AS/400, iSeries, and System i: List Price, $49.95
    Getting Started with PHP for i5/OS: List Price, $59.95
    The System i RPG & RPG IV Tutorial and Lab Exercises: List Price, $59.95
    The System i Pocket RPG & RPG IV Guide: List Price, $69.95
    The iSeries Pocket Database Guide: List Price, $59.00
    The iSeries Pocket Developers' Guide: List Price, $59.00
    The iSeries Pocket SQL Guide: List Price, $59.00
    The iSeries Pocket Query Guide: List Price, $49.00
    The iSeries Pocket WebFacing Primer: List Price, $39.00
    Migrating to WebSphere Express for iSeries: List Price, $49.00
    iSeries Express Web Implementer's Guide: List Price, $59.00
    Getting Started with WebSphere Development Studio for iSeries: List Price, $79.95
    Getting Started With WebSphere Development Studio Client for iSeries: List Price, $89.00
    Getting Started with WebSphere Express for iSeries: List Price, $49.00
    WebFacing Application Design and Development Guide: List Price, $55.00
    Can the AS/400 Survive IBM?: List Price, $49.00
    The All-Everything Machine: List Price, $29.95
    Chip Wars: List Price, $29.95

    Zephyr Targets Client Access with Replacement Program IBM Adds ‘Rich UI’ Design Tool to Rational Business Developer

    Leave a Reply Cancel reply

Volume 8, Number 42 -- December 10, 2008
THIS ISSUE SPONSORED BY:

Profound Logic Software
WorksRight Software
Twin Data

Table of Contents

  • Four Ways to Avoid Problems Caused by Global Data
  • Where’s the Service Program?
  • Admin Alert: The Dangers of User Profiles with Privileges

Content archive

  • The Four Hundred
  • Four Hundred Stuff
  • Four Hundred Guru

Recent Posts

  • Meet The Next Gen Of IBMers Helping To Build IBM i
  • Looks Like IBM Is Building A Linux-Like PASE For IBM i After All
  • Will Independent IBM i Clouds Survive PowerVS?
  • Now, IBM Is Jacking Up Hardware Maintenance Prices
  • IBM i PTF Guide, Volume 27, Number 24
  • Big Blue Raises IBM i License Transfer Fees, Other Prices
  • Keep The IBM i Youth Movement Going With More Training, Better Tools
  • Remain Begins Migrating DevOps Tools To VS Code
  • IBM Readies LTO-10 Tape Drives And Libraries
  • IBM i PTF Guide, Volume 27, Number 23

Subscribe

To get news from IT Jungle sent to your inbox every week, subscribe to our newsletter.

Pages

  • About Us
  • Contact
  • Contributors
  • Four Hundred Monitor
  • IBM i PTF Guide
  • Media Kit
  • Subscribe

Search

Copyright © 2025 IT Jungle