• The Four Hundred
  • Subscribe
  • Media Kit
  • Contributors
  • About Us
  • Contact
Menu
  • The Four Hundred
  • Subscribe
  • Media Kit
  • Contributors
  • About Us
  • Contact
  • Functions Can Modify Parameters, Too

    January 14, 2004 Hey, Ted

    Steven Gray suggested that it’s a good idea for an RPG function subroutine to return a data structure. I think he’s on the right trail but barking up the wrong tree. Barbara Morris pointed out that it’s more efficient to modify a data structure as a parameter of a subprocedure. I suggest that the best approach is to combine the strengths of the two methods.

    I understand and fully appreciate the enthusiasm many programmers feel for functions. Compared with traditional RPG coding methods, nesting an %INT function within a %SUBST function within a %CHAR function, for example, eliminates intermediate work fields and reduces lines of code.

    What programmers seem to forget is that a function may, and sometimes should, modify its parameters. C’s scanf( ) function is a good example. Scanf( ) reads data from the standard input stream and assigns the data to one or more variables, which are passed by the caller through pointer arguments. At the same time, scanf( ) returns an integer value indicating the number of values that were successfully read and assigned to variables.

    To return to Steven Gray’s example, I propose that the GetCustDS function should return a value, as Steven Gray suggests, but I think the return value should be an indicator value to indicate success or failure. I agree with Barbara Morris that the customer data structure should be passed to the caller through a modified parameter.

    The following copybook source member contains the CustDS data structure from Steven Gray’s original article and procedure prototypes to three function subprocedures. Notice that each function returns an indicator value:

    D CustDS          DS                  qualified
    D   CustNum                      5P 0
    D   Name                        40
    D   Addr                        40
    D   CityStZip                   40
    D   CurBal                       9S 2
    D   CredBal                      9S 2
    D
    D OpenCust        PR              N
    D
    D CloseCust       PR              N
    D
    D GetCustDS       PR              N
    D  zCustNum                      5P 0 Value
    D  zDS                                LikeDS(CustDS)
    

    As Steven Gray recommends, I have created a module from which a service program could be built in order to contain the implementation of the functions:

    H option(*srcstmt: *nodebugio)
    H nomain
    
    FCustomer  IF   E           K Disk    UsrOpn
    
     /Copy Prototypes,CustRtns
    
    P OpenCust        B                   Export
    D OpenCust        PI              N
    D
    C                   Open(E)   Customer
    C                   Return    Not %Error
    P                 E
    
    P CloseCust       B                   Export
    D CloseCust       PI              N
    D
    C                   Close(E)  Customer
    C                   Return    Not %Error
    P                 E
    
    P GetCustDS       B                   Export
    D GetCustDS       PI              N
    D  zCustNum                      5P 0 Value
    D  zDS                                LikeDS(CustDS)
    D
    C     zCustNum      Chain     cFmt
    C                   If        %Found
    C                   Eval      zDS.CustNum = CustomerNo
    C                   Eval      zDS.Name = %trim(FName) + ' ' +
    C                                        %trim(MidInit) + ' ' +
    C                                        %trim(LName) + ' '
    C                   Eval      zDs.Addr       = address1
    C                   Eval      zDs.CityStZip  = %trim(city)  + ', ' +
    C                                              %trim(state) + '  ' +
    C                                              %trim(zipcode)
    C                   Eval      zDs.CurBal     = Balance
    C                   Eval      zDs.CredBal    = Credit - Balance
    C                   Endif
    C                   Return    %Found
    C
    P GetCustDS       E
    

    I have modified the GetCustDS function to return an indicator value, which lets the caller know whether the requested customer was found in the database. I have created two other functions to open and close the customer file. These return indicator variables advise the caller of the success or failure of their respective operations.

    The following example shows how a caller would access these routines:

    H Option(*SrcStmt: *NoDebugIO)
                               
    D* *ENTRY PLIST
    D CustTest        PR                  ExtPgm('CUSTTEST1')
    D  parmCustNbr                   5S 0
    D CustTest        PI
    D  parmCustNbr                   5S 0
                        
    D zCustNum        S              5P 0
    D IsOpen          S               N
    D CustomerExists  S               N
    
    /Copy Prototypes,CustRtns
    
    C             Eval      IsOpen = OpenCust
    C             If        Not IsOpen
    C*              file did not open -- do something
    C             EndIf
    C
    C             Eval      zCustNum = parmCustNbr
    C             Eval      CustomerExists = GetCustDS (zCustNum: CustDS)
    C             If        Not CustomerExists
    C               the customer is not on file -- do something
    C             EndIf
    C
    C             CallP     CloseCust
    C             Eval      *INLR = *On
    C             Return
    

    Notice that the OpenCust and GetCustDS functions are called with the EVAL operation. The return values are assigned to indicator variables IsOpen and CustomerExists. The programmer can use these values to proceed properly. Steven Gray’s original code indicated a not-found condition by setting the customer number to zero, a technique I used until I was faced with a situation in which all possible key values were valid.

    The CloseCust function also returns a value, but since I don’t care whether it succeeds or fails, I’ve called it with CALLP instead of EVAL. In other instances, there may be reasons why I should care about the status of the close operation. In such cases, I would call CloseCust with EVAL.

    One can eliminate the indicator variables by using the functions with other operations, such as DOW, DOU, and IF, as the following example shows:

    C         If        Not OpenCust
    C*          file did not open -- do something
    C         Eval      *INLR = *On
    C         Return
    C         EndIf
    C
    C         If        GetCustDS (zCustNum: CustDS)
    C*          the customer is on file -- do something
    C         Else
    C*           the customer is not on file -- do something else
    C         EndIf
    

    It is unlikely, but possible, that the GetCustDS function could fail. It would not be inappropriate to say that the GetCustDS function needs to return two values–one to indicate whether the customer was found in the database and another to indicate whether the operation succeeded or failed. Yet a function can only return one value. That problem is easily resolved by letting the caller handle the error. In the following example, RPG’s MONITOR operation traps an error:

    C         Monitor
    C         If        GetCustDS (zCustNum: CustDS)
    C*          the customer is on file -- do something
    C         Else
    C*          the customer is not on file -- do something else
    C         EndIf
    C         On-Error
    C         Eval      ErrorRaised = *On
    C         EndMon
    

    I like the idea of hiding I/O routines in subprocedures. Calling one well-designed routine from a lot of places sure beats coding the same logic in a lot of places. Thanks for the discussion.

    –Cletus the Codeslinger

    Share this:

    • Reddit
    • Facebook
    • LinkedIn
    • Twitter
    • Email

    Tags:

    Sponsored by
    Rocket Software

    Meet digital age demands while maximizing your IT investment.

    Future-proof your mission-critical applications with Rocket® Solutions for IBM® i that keep your business ahead of the curve.

    Learn More

    Share this:

    • Reddit
    • Facebook
    • LinkedIn
    • Twitter
    • Email

    Ultra Density Optical One Step Closer to Reality on iSeries Two Crazy iSeries Ideas for 2004

    Leave a Reply Cancel reply

Volume 4, Number 1 -- January 14, 2004
THIS ISSUE
SPONSORED BY:

T.L. Ashford
Damon Technologies
WorksRight Software
SuSE Linux
iTera

Table of Contents

  • Why SQL? Why Now?
  • Deleting with a Generic File Name
  • Functions Can Modify Parameters, Too
  • Admin Alert: Three Common Mistakes in CL Administration
  • OS/400 Alert: Spoofing and Demonstrations

Content archive

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

Recent Posts

  • 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
  • IBM Unveils Manzan, A New Open Source Event Monitor For IBM i
  • Say Goodbye To Downtime: Update Your Database Without Taking Your Business Offline
  • i-Rays Brings Observability To IBM i Performance Problems
  • Another Non-TR “Technology Refresh” Happens With IBM i TR6
  • IBM i PTF Guide, Volume 27, Number 18

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