TechTip: Write Modular, Dynamic Code with Procedure Pointers PDF Print E-mail
Tips & Techniques - RPG
Written by Kevin Forsythe   
Friday, 19 June 2009 02:00

Support MC Press - Visit Our Sponsors

 

Forums Sponsor

 

 Popular Forums

POPULAR FORUMS
  1. Parsing XML using XSL in RPGLE (494 views)
  2. Upload TXT to Source PF (441 views)
  3. Comment on: TechTip: Automate Data Transfers Using FTP (349 views)
  4. VARLEN in DDS vs. VARCHAR in DDL (346 views)
  5. "When you're wrong, admit it quickly and emphatically" (337 views)
  6. Thanks! (220 views)
  7. Great news for users of System i XLPARSE (179 views)
  8. Problem with AIR09_03 and V6R1 issue (165 views)
  9. Is any tool available for validating XML with DTD/XSL in RPGLE (154 views)
  10. RPG Programmer Analyst (Midrange) Position In Northern New Jersey (134 views)

Forums

 

Search Sponsor
  
 

 Popular Searches

POPULAR SEARCHES
1. sql2xls
2. Tom Snyder
3. PHP
4. PDF
5. subfile
6. XML
7. java
8. gregory
9. ftp
10. sql2xml

Search

Rather than create multiple versions of code to do different things with data, this technique allows you to have only one copy of that logic.

 

As we try to develop more modular code, one of the problems that we encounter is how to integrate modules or procedures that need to process more than a single record or row of data. We already know that we can easily pass parameters or arguments between procedures that hold all the data we need if we are processing only a single row or record. But what if we want to call a process that processes all the records for a selected part, or all the records for a given PO, or any similar process? What if we want to pass an array or multiple-occurrence data structure? Those have some limitations that make them more difficult to implement.

 

An elegant solution to this type of situation is to use a procedure pointer. Figure 1 illustrates how an application program can dynamically integrate with a service program to process all the records for a given part.

 

 061908ForsytheFigure_1

Figure 1: An application program can dynamically integrate with a service program.

 

In this example, the application program is an interactive program that allows the user to select a part number and then prints a report listing all the data for that part. In this application, let's assume that collecting the data for that part is a complex process that has been encapsulated into its own service program. The application program will get a part number from the user and then pass it to the service program. The logic inside the service program will use that part number to build a list of records to process. For each record in that list, the service program will make a call back to the subprocedure in the application program. Once all the records are processed, control returns to the mainline in the application program. This lets the application program leverage modularized code in the service program that handles multiple records.

 

Below is the sample code for the application program. The GetParts subprocedure is a commonly used subprocedure deployed through a service program. That subprocedure receives three parameters: the part number being processed, the data structure to hold the data for each part being processed, and the procedure pointer for the MyProc subprocedure in this program. Note that the %ADDR function is used to get the address of the P_Data data structure, and the %PADDR function is used to get the procedure address of the MyProc subprocedure in this program. In this sample program, the MyProc subprocedure will display the description of each record processed by the GetParts subprocedure.

 

 

D GetParts        PR                                     

D P_Part                        10                       

D P_Data_Ptr                      *                      

D P_Proc_Ptr                      *   PROCPTR            

                                                         

D MyProc          PR                                      

                                                         

D P_Data        E DS                  EXTNAME(PartMast)  

D Data_Ptr                        *                      

D Proc_Ptr                        *   PROCPTR            

                                                          

 /Free                                                   

                                                         

   DSPLY 'Part?' ' ' PartNo;                             

   Data_Ptr = %ADDR(P_Data);                             

   Proc_Ptr = %PADDR(MyProc);                   

                                                

   CALLP GetParts(PartNo:Data_Ptr:Proc_Ptr);    

                                                

   *INLR = *ON;                                  

                                                

   Return;                                      

 /End-Free                                      

                                                

P MyProc          B                   EXPORT    

D MyProc          PI                            

                                                

 /Free                                          

                                                

  DSPLY DESCRIPT ' ';                            

                                                

  Return;                                       

 /End-Free         

P MyProc          E

 

 

Below is the sample code for the service program. This service program defines two procedures: Get Parts, which handles the process of selecting all the records for the given part, and ProcessRow, which is a surrogate or proxy for the MyProc subprocedure in the application program. The EXPROC keyword indicates that this procedure is identified by its address rather than its name. At run time, when this procedure is called, control is passed to the address specified by the Proc_Ptr variable.

 

This sample program uses relatively simple SQL processes to build a list of records to process and then loops through them one at a time. For each record read, the ProcessRow function is called, passing control back to the MyProc sub procedure in the application program. The data for each record is loaded into P_Data, which shares the same memory address as the P_Data in the application program, which means that it is available for use in MyProc. This eliminates the need to pass data into the subprocedure.

 

 

H  NOMAIN                                                    

                                                              

D ProcessRow      PR                  EXTPROC(Proc_Ptr)      

D Proc_Ptr        S               *   PROCPTR INZ(*NULL)     

                                                             

D GetParts        PR                                          

D P_Part                        10                           

D P_Data_Ptr                      *                          

D P_Proc_Ptr                      *   PROCPTR                

                                                              

P GetParts        B                   EXPORT                 

D GetParts        PI                                         

D P_Part                        10                           

D P_Data_Ptr                      *                           

D P_Proc_Ptr                      *   PROCPTR                

                                                             

D P_Data        E DS                  EXTNAME(PartMast)      

D                                     BASED(P_Data_Ptr)       

                                                             

 /Free                                                       

                                                             

    Proc_Ptr = P_Proc_PTr;                                   

                                                             

  EXEC SQL DECLARE C1 CURSOR FOR                             

           SELECT * FROM PARTMAST                            

           WHERE PARTNO = :P_PART;                           

                                                              

  EXEC SQL OPEN C1;                                          

                                                             

  EXEC SQL FETCH FROM C1 INTO :P_Data;                       

                                                              

  DOW SQLCODE = 0;                                           

                                                             

    CALLP ProcessRow();                           

                                                   

    EXEC SQL FETCH FROM C1 INTO :P_Data;          

  ENDDO;                                          

                                                  

  Return;                                         

 /End-Free                                         

P GetParts        E                               

 

The key thing to keep in mind is that, in this example, the service program includes an already-written subprocedure that performs the frequently required and relatively complex task of gathering all the records related to a given part. Rather than copying that code or creating multiple versions of it that do different things with the data, this technique allows you to have only one copy of that logic. That one well-written subprocedure can then call back to a given subprocedure in the application program that is driving this whole process and allow that subprocedure to determine what to do with the each record processed.


Kevin Forsythe
About the Author:

Kevin Forsythe has worked on IBM midrange systems for 25 years. With many years of experience in programming, analysis, consulting, and instruction, he is uniquely skilled at making difficult material more easily understood. His comprehensive background includes practical application, education, and research and provides a perspective that allows him to help others steer their way through the technical maze that surrounds them. Kevin is a member of COMMON's Speaker Hall of Fame, and he currently develops applications for DriveTime.

 

Kevin has written numerous articles on a variety of AS/400/iSeries/System i/IBM i topics. He authored the bestselling book SQL for eServer i5 and iSeries and co-authored IBM i5/iSeries Primer, Fourth Edition and HTML for the Business Developer.

Read More >>
Last Updated on Friday, 19 June 2009 02:00
  No Comments.
Discuss...
   MC-STORE.COM