• The Four Hundred
  • Subscribe
  • Media Kit
  • Contributors
  • About Us
  • Contact
Menu
  • The Four Hundred
  • Subscribe
  • Media Kit
  • Contributors
  • About Us
  • Contact
  • Guru Classic: Automatic Or Static Storage?

    January 16, 2019 Susan Gantner

    Author’s Note: This tip was first published in August 2008. One thing that has changed in the intervening 10-plus years is that I find a lot more RPGers regularly using subprocedures now. Something that hasn’t really changed much is that many of those using subprocedures still don’t fully understand the behavioral differences between automatic and static storage. The concepts and handling of automatic versus static storage haven’t really changed. So the only modifications I’ve made for this reprise of the tip is to update the style of the code example.

    If you write RPG subprocedures, you should know about the differences between automatic and static storage. (If you don’t write subprocedures, shame on you!) I’ve found that many writers and/or users of subprocedures don’t fully understand the differences. So let’s start at the beginning.

    By default, fields (i.e., standalone fields, data structures, arrays, etc.) defined inside a subprocedure (a.k.a. local fields) use automatic storage. This means that the storage doesn’t exist until the procedure is called and it is cleaned up when the procedure returns to its caller. Of course, since the storage goes away between calls to the procedure, that means the values are reinitialized between each call to the procedure (and the status of the LR indicator has no impact.)

    This differs from fields defined outside of subprocedures (i.e., in the main part of the program – or before the first P spec in the source member) that use static storage. Static storage exists from the time the program is called until the activation group it is running in ends or until the job ends. Notice though that the values in static fields defined outside the P specs are re-initialized on return if the LR indicator was turned on; with LR off, the values remain the same between multiple calls to the program.

    You have no choice for the type of storage used for the global fields, but for the local fields in your procedures, you do have the option of making them static by coding the STATIC keyword. This makes them behave almost the same as the global fields. They will retain their values between multiple calls to the procedure.

    However, there is still a difference in behavior between local static fields in a procedure and global fields. The local static fields are not impacted by the status of the LR indicator, so they retain their values between calls to the program even if LR was set on before the return.

    To see if you’ve got the idea, study the following code and then try to answer these questions.

    • On the first call in the job to this *PGM, what values will be displayed for AutoCount, StaticCount, and GlobalCount on each of the three calls?
    • After the program has run once, if you were to call it again right away in the same job, what values would you see for them on the second iteration of the program?
    • If you issue a RCLACTGRP QILE (or sign off and back on) and call the program a third time, what values do I see?
           Ctl-Opt DftActGrp(*NO)  ActGrp('QILE') Option(*SrcStmt);
    
           Dcl-Pr ProcAuto End-Pr;
    
           Dcl-S I Uns(5);
           Dcl-S GlobalCount Packed(3) Inz;  
    
           For I = 1 to 3;   // Call the subprocedure 3 times
             ProcAuto();
           EndFor;
    
           *INLR = *On;
    
           Dcl-Proc ProcAuto;
    
           Dcl-Pi *N End-Pi;
    
           Dcl-S AutoCount   Packed(3);
           Dcl-S StaticCount Packed(3)  Static;
    
           Dcl-S Reply       Char(1); // Used to hold Dsply text on screen  
     
           StaticCount += 1;
           AutoCount += 1;
           GlobalCount += 1;
           Dsply (' AutoCount=' + %Char(AutoCount) +
                 ', StaticCount=' + %Char(StaticCount) +
                 ', GlobalCount=' + %Char(GlobalCount)) ' ' Reply; 
    
           End-Proc ProcAuto;  
    

    If you answered the following for question 1…

    AutoCount=1, StatCount=1, GlobalCount=1
    AutoCount=1, StatCount=2, GlobalCount=2
    AutoCount=1, StatCount=3, GlobalCount=3
    

    . . . and the following for question 2 . . .

    AutoCount=1, StatCount=4, GlobalCount=1
    AutoCount=1, StatCount=5, GlobalCount=2
    AutoCount=1, StatCount=6, GlobalCount=3
    

    . . . and the following for question 3 . . .

    AutoCount=1, StatCount=1, GlobalCount=1
    AutoCount=1, StatCount=2, GlobalCount=2
    AutoCount=1, StatCount=3, GlobalCount=3
    

    . . . congratulations, you’ve got it!

    Of course, all this begs the question of how to initialize or re-initialize static values in a procedure when you need to? The simple answer is to do it manually in the logic, with something like a CLEAR or EVAL operation.

    But how do you signal the subprocedure when to re-initialize the static fields? Presumably since you made them static, they should not be initialized on every call. This requires a bit of thought and there are many potential solutions. Many people have a special parameter that is passed to tell the procedure to initialize. It might be a *NoPass parameter at the end of the list that is only used when initialization is required. Another popular option is to make all the parameters *NoPass and when the procedure is called with %Parms = 0, it is the signal to reinitialize.

    There are many other options that could be used. The ones you use will likely be different for internal subprocedures versus procedures in a Service Program. But the important thing to remember is that you’ll need to accommodate this in your design if you need to use static fields in a subprocedure.

    Now that we’ve covered the different types of storage available to us, when do you choose one over the other? In my own experience, I’ve had very little occasion to use static storage for my local variables. I’m an enthusiastic user of local variables and, for the most part, the fact that they are by default automatically cleaned up and reset on each call is a plus.

    If I have a rare occasion when I need to keep a value around across multiple calls — perhaps to count or accumulate something across multiple calls to a procedure — I tend to declare the variable globally and pass it into the procedure as a variable and using the return value to get the updated value back. I don’t update the global variable directly from the procedure because I prefer to restrict my data access and updates in procedures to local data. While it does require a little extra code to pass the parameter and return the new value, I consider that a good thing because it means the call to the procedures self-documents what data is being impacted by the called routine. To me, that’s one of the major advantages of using subprocedures over subroutines.

    Of course, this assumes that the counter or accumulated value is needed back in the main program or caller. If not, then simply declaring it as static and then finding a method to reinitialize it (if necessary) works fine.

    In this tip, I’ve limited the discussion to local variables, not local files. The use of local files and the important role of the STATIC keyword with them were covered in a tip by Jon Paris here a while ago. I encourage you to check it out to continue your explorations in the use (or not) of static storage.

    Susan Gantner, an IBM Champion and co-author of the popular Redbook, Who Knew You Could Do That with RPG IV, is one of the top speakers/writers/trainers on IBM i development topics. She is a partner at Partner400 and System i Developer, and she hosts the RPG & DB2 Summit twice per year with partners Jon Paris and Paul Tuohy.

    RELATED STORIES

    Subprocedures: Better than Subroutines

    The Geezer’s Guide To Free-Form RPG, Part 4: Prototypes and Procedure Interfaces

    Files in Subprocedures

    Subprocedure Return Values–Food for Thought

    Share this:

    • Reddit
    • Facebook
    • LinkedIn
    • Twitter
    • Email

    Tags: Tags: 400guruclassic, FHGC, Four Hundred Guru Classic, IBM i, RPG

    Sponsored by
    Rocket Software

    Disrupt Without Disruption

    For over 35 years, Rocket Software’s solutions have empowered businesses to modernize their infrastructure, unlock data value, and drive transformation – all while ensuring modernization without disruption.

    Learn How

    Share this:

    • Reddit
    • Facebook
    • LinkedIn
    • Twitter
    • Email

    Guru Classic: A Bevy of BIFs – %SCAN and %CHECK IBM i PTF Guide, Volume 21, Number 2

    Leave a Reply Cancel reply

TFH Volume: 29 Issue: 3

This Issue Sponsored By

  • RPG & DB2 Summit
  • RPG & DB2 Summit
  • RPG & DB2 Summit

Table of Contents

  • Guru Classic: Automatic Or Static Storage?
  • Guru Classic: A Bevy of BIFs – %SCAN and %CHECK
  • Guru Classic: Call Again And Again And Again . . .

Content archive

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

Recent Posts

  • To Comfort The Afflicted And Afflict The Comfortable
  • How FalconStor Is Reinventing Itself, And Why IBM Noticed
  • Guru: When Procedure Driven RPG Really Works
  • Vendors Fill In The Gaps With IBM’s New MFA Solution
  • IBM i PTF Guide, Volume 27, Number 27
  • With Power11, Power Systems “Go To Eleven”
  • With Subscription Price, IBM i P20 And P30 Tiers Get Bigger Bundles
  • Izzi Buys CNX, Eyes Valence Port To System Z
  • IBM i Shops “Attacking” Security Concerns, Study Shows
  • IBM i PTF Guide, Volume 27, Number 26

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