• The Four Hundred
  • Subscribe
  • Media Kit
  • Contributors
  • About Us
  • Contact
Menu
  • The Four Hundred
  • Subscribe
  • Media Kit
  • Contributors
  • About Us
  • Contact
  • CONST Doesn’t Mean You Can’t Change It

    October 20, 2015 Ted Holt

    You can pass parameters to an RPG subprocedure in three ways: by reference, by read-only reference, and by value. (I have written about this before.) My favorite method is read-only reference. I use it as often as I can. Would you believe that it is possible to change the value of a variable that is passed to a subprocedure by read-only reference? Since you would probably do so only inadvertently, it’s good to understand how it can happen.

    To pass a parameter by read-only reference, include the CONST keyword in the procedure prototype and the procedure interface.

    D Process         pr
    D  inSection                          like(Section) const
    
    P Process         b
    D                 pi
    D  inSection                          like(Section) const
    

    If the program from which this code was taken tries to modify inSection within the Process subprocedure, like this:

    eval inSection = 'XX'
    

    The compiler heartlessly responds with message RNF5346: “The operation modifies the field, but the field cannot be modified.” And so the compilation fails.

    No, to modify inSection, you have to be sneaky. (Or in my case, stupid.) Here’s how it’s done.

    Assume a database table:

    create table Specs
       (Section    char(2),
        Sequence   dec(3),
        Position   dec(3),
        Text       char(50),
       primary key (Section, Sequence))
       rcdfmt Spec;
    
    insert into Specs values
    ('BB',  1,  1, 'XXXXXXXXXXXXXXX'),
    ('BB',  2,  1, 'XXXXXXXXXXXXXXX'),
    ('BB',  3, 13, 'XXX'), ('BB',  4, 12, 'XXX'),
    ('BB',  5, 11, 'XXX'), ('BB',  6, 10, 'XXX'),
    ('BB',  7,  9, 'XXX'), ('BB',  8,  8, 'XXX'),
    ('BB',  9,  7, 'XXX'), ('BB', 10,  6, 'XXX'),
    ('BB', 11,  5, 'XXX'), ('BB', 12,  4, 'XXX'),
    ('BB', 13,  3, 'XXX'), ('BB', 14,  2, 'XXX'),
    ('BB', 15,  1, 'XXX'), 
    ('AA',  1,  4, 'XXXXXXXXX'),
    ('AA',  2,  2, 'XX         XX'),
    ('AA',  3,  1, 'XX           XX'),
    ('AA',  4, 11, 'XXX'),
    ('AA',  5,  9, 'XXX'),
    ('AA',  6, 11, 'XXX'),
    ('AA',  7,  1, 'XX           XX'),
    ('AA',  8,  2, 'XX         XX'),
    ('AA',  9,  4, 'XXXXXXXXX');
    

    Here’s a printer file:

    A          R HEADER                    SKIPB(1)   
    A                                     1'==BEGIN=='
    A          R DETAIL                    SPACEB(1)  
    A            MESSAGE       80         1           
    A          R TRAILER                   SPACEB(1)  
    A                                     1'==END=='  
    

    And finally, an RPG program:

    H dftactgrp(*no) actgrp(*new) option(*srcstmt: *nodebugio)
    
    FSpecs     if   e           k disk
    FQAD0040P  o    e             printer
    
    D Process         pr
    D  inSection                          like(Section) const
    
     /free
         *inlr = *on;
         read Spec;
         dow not %eof(Specs);
            write Header;
            Process (Section);
            write Trailer;
         enddo;
         return;
     /end-free
    
    P Process         b
    D                 pi
    D  inSection                          like(Section) const
     /free
         dow not %eof(Specs)
         and Section = inSection;
            clear Message;
            %subst(Message: Position) = Text;
            write Detail;
            read Spec;
         enddo;
     /end-free
    
    P Process         e
    

    Notice the Process subroutine. Its purpose is obviously to print all the data for whichever section is specified in the inSection parameter. Just glancing at the data and this program, you would expect this two-page report:

    ==BEGIN==
       XXXXXXXXX
     XX         XX
    XX           XX
              XXX
            XXX
              XXX
    XX           XX
     XX         XX
       XXXXXXXXX
    ==END==
    < . . . imagine a page break here . . . >
    ==BEGIN==
    XXXXXXXXXXXXXXX
    XXXXXXXXXXXXXXX
                XXX
               XXX
              XXX
             XXX
            XXX
           XXX
          XXX
         XXX
        XXX
       XXX
      XXX
     XXX
    XXX
    ==END==
    

    But, no, you’d get a one-page report, like this:

    ==BEGIN==
       XXXXXXXXX
     XX         XX
    XX           XX
              XXX
            XXX
              XXX
    XX           XX
     XX         XX
       XXXXXXXXX
    XXXXXXXXXXXXXXX
    XXXXXXXXXXXXXXX
                XXX
               XXX
              XXX
             XXX
            XXX
           XXX
          XXX
         XXX
        XXX
       XXX
      XXX
     XXX
    XXX
    ==END==
    

    Here’s why.

    The main routine passes the address of the Section variable to the Process subprocedure. This means that inSection (in the subprocedure) and Section (throughout the entire program) are two names for the same spot in memory. When Process reads the Specs table, the system changes the value of Section, which is also the value of inSection. Consequently, the control break never occurs and the loop stops at end of file.

    Global variables cause a lot of grief and I try to avoid them, but in all fairness, passing lots of parameters between subprocedures can get mighty unwieldy.

    There are several ways to fix this problem. Perhaps the easiest is to pass the section ID by value.

    D Process         pr
    D  inSection                          like(Section) value
    
    P Process         b
    D                 pi
    D  inSection                          like(Section) value
    

    This change gives you the two-page report you expected.

    Here’s another way to change the value of a variable that is passed by read-only reference. I’ll modify the preceding program slightly in order to illustrate.

    H dftactgrp(*no) actgrp(*new) option(*srcstmt: *nodebugio)
    
    FSpecs     if   e           k disk
    
    D Process         pr
    D  inSection                          like(Section)  const
    
    D BR549           pr                  extpgm('BR549')
    D  inSection                          like(Section)  const
    
     /free
         *inlr = *on;
         read Spec;
         dow not %eof(Specs);
            Process (Section);
            read Spec;
         enddo;
         return;
     /end-free
    
    P Process         b
    D                 pi
    D  inSection                          like(Section)  const
    
     /free
         BR549 (inSection);
     /end-free
    
    P Process         e
    

    The program passes the address of Section to subprocedure Process, which knows the parameter as inSection. The subprocedure calls program BR549, passing the section value along by read-only reference. Now let’s take a look at BR549.

    pgm (&inSection)
    
       dcl  &inSection   *char  2
    
       chgvar  &inSection   'ZZ'
       return
    
    endpgm
    

    Even though the RPG program thinks the CL program won’t modify the parameter, the CL program has other ideas. In fact, the CL program doesn’t even know that the RPG program thinks the parameter won’t be modified.

    I highly recommend passing parameters by read-only reference, but be aware that the CONST keyword isn’t foolproof.

    RELATED STORY

    Parameter Passing and Performance

    Share this:

    • Reddit
    • Facebook
    • LinkedIn
    • Twitter
    • Email

    Tags:

    Sponsored by
    Midrange Dynamics North America

    Git up to speed with MDChange!

    Git can be lightning-fast when dealing with just a few hundred items in a repository. But when dealing with tens of thousands of items, transaction wait times can take minutes.

    MDChange offers an elegant solution that enables you to work efficiently any size Git repository while making your Git experience seamless and highly responsive.

    Learn more.

    Share this:

    • Reddit
    • Facebook
    • LinkedIn
    • Twitter
    • Email

    Sponsored Links

    Connectria:  Need help managing your IBM i? Trust us as an extension of your IT department.
    HelpSystems:  How do you use IBM i? Your peers want to know! Take the survey >
    Rocket Software:  Mobile app development and deployment solution for IBM i. Download FREE trial!

    IBM Updates PowerVM Hypervisor, PowerVC OpenStack Accur8 Takes Aim at Data Virtualization Opportunity

    Leave a Reply Cancel reply

Volume 15, Number 21 -- October 20, 2015
THIS ISSUE SPONSORED BY:

WorksRight Software
PowerTech
Storagepipe

Table of Contents

  • Developers Can Improve Security and Reduce the Administrative Cost of Security
  • CONST Doesn’t Mean You Can’t Change It
  • DB2 for i 7.1 TR10 and i 7.2 TR2 Features, Part 2

Content archive

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

Recent Posts

  • FAX/400 And CICS For i Are Dead. What Will IBM Kill Next?
  • Fresche Overhauls X-Analysis With Web UI, AI Smarts
  • Is It Time To Add The Rust Programming Language To IBM i?
  • Is IBM Going To Raise Prices On Power10 Expert Care?
  • IBM i PTF Guide, Volume 27, Number 20
  • POWERUp 2025 –Your Source For IBM i 7.6 Information
  • Maxava Consulting Services Does More Than HA/DR Project Management – A Lot More
  • Guru: Creating An SQL Stored Procedure That Returns A Result Set
  • As I See It: At Any Cost
  • IBM i PTF Guide, Volume 27, Number 19

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