12
Tue, Nov
5 New Articles

Let's Build a Procedure

RPG
Typography
  • Smaller Small Medium Big Bigger
  • Default Helvetica Segoe Georgia Times

Procedures (or "subprocedures," as are they are called in RPG IV) are the fundamental building blocks of all RPG IV applications. If you are not regularly using procedures in your RPG IV code, you are simply writing RPG III programs using RPG IV syntax. Being an RPG III programmer in RPG IV clothing isn't a bad thing to be, but you need to take that next step toward writing true RPG IV code.

To get to that point, you need to start using procedures. Procedures are a bit different from RPG's traditional subroutines in that they are more than just a repeated section of code. Procedures are not a replacement for subroutines; instead, they are a different kind of technology whose capability overlaps the capability of subroutines. In other words, you can continue to write subroutines, but there is absolutely no compelling reason to do so. Everything you do with subroutines can be accomplished with procedures.

From a high-level perspective, procedures differ from subroutines as follows:

  • Procedures accept parameters just like programs do but with more optional features. Subroutines do not accept parameters.
  • Procedures can be used as an extension to the RPG IV language. In other words, you can create a procedure, such as TOUPPER, whose purpose in life is to convert lowercase to uppercase, and then use that procedure within a conditional statement or on an assignment statement. You can't do that with subroutines.
  • You can declare fields within procedures, and those fields will be isolated to the procedure. This means that outside of the procedures, those fields do not exist; they are not known to the other procedures or mainline calcs in the program. Therefore, you can use more meaningful names for work fields and other variables when they are declared within a procedure. (And that means you can avoid using symbols such as #, @, and $ in field names!)
  • Procedures can be compiled and stored separately from the program itself. You can actually create a source member that contains nothing but a few of your favorite procedures, compile it, and then link to it at compile time, just as if the procedures were embedded in the main program itself. Subroutines, however, must always be declared in the source of the main program.

These few points are just the beginning of the advantages of procedures over subroutines.

Building That First Procedure

Probably the most difficult step in using procedures is creating that first working procedure. To do this, you need a couple of new statements in RPG IV that declare the procedure. Those statements are the P specifications.

The P specifications declare the start and end points of a procedure. You need two P specifications for each procedure you create: one to indicate the start of the procedure code and one to indicate the end of the procedure code.

Think of the P specification of a procedure as the equivalent of the BEGSR and ENDSR opcodes. For example, to declare a subroutine named TOUPPER, you might have the following specified:

     CSR   ToUpper       Begsr

      **  subroutine code goes here

     CSR   endToUpper    Endsr

To declare a procedure named TOUPPER, you would have the following code with P specifications instead of BEGSR and ENDSR statements:

     P ToUpper         B

        //  procedure code goes here

     P ToUpper         E

OK, the difficult part is over. Now, you need to migrate your subroutine-writing skills to procedure-writing skills. To do this, you first need to have an example subroutine that you want to migrate to a procedure. Illustrated below is the example RPG IV source code that uses work fields and a subroutine to convert lowercase to uppercase. Granted, I could have just call the XLATE opcode and avoided the call to the subroutine altogether, but I needed something to illustrate this example.

D UPPER           C                   'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
D lower           C                   'abcdefghijklmnopqrstuvwxyz'
D TU_Work         S           1024A   Varying 

D work1           S           1024A   Varying
D work2           S           1024A   Varying

C     CustNo        Chain     CustRec
C                   If        %Found()  
C                   move      CSTNAME       TU_WORK
C                   exsr      ToUpper
C                   move      TU_WORK       Work1

C                   move      OLDNAME       TU_Work
C                   exsr      ToUpper
C                   move      TU_WORK       Work2
C                   if        Work1 = Work2
 **  Old/New names are identical...
C                   endif
C                   endif

CSR   ToUpper       Begsr
C
C     lower:UPPER   XLate     TU_Work       TU_Work
     
CSR   endToUpper    Endsr

In this example, a customer record is retrieved from the customer master file, and the CSTNAME field from that file is going to be compared to the previous value for that field. This allows you to verify whether or not the name of the customer has changed yet ignore the upper/lowercase differences between the two fields.

Now, rewrite this using RPG IV syntax. First, create just the procedure itself, without changing any of the mainline calc's logic. Here is a fundamental version of the TOUPPER subroutine, written as a procedure.

P ToUpper         B
D ToUpper         PI

C     lower:UPPER   XLate     TU_Work       TU_Work
C                   return

P ToUpper         E

You need to add three lines of code to the TOUPPER procedure to make it a functioning component. The D specification that immediately follows the P specification is used to identify the procedure equivalent of the *ENTRY PLIST. In other words, this declares the parameter list for the procedure. This is known as the "procedure interface." So remember, the term "procedure interface" means "the procedure's *ENTRY PLIST."

Since you're not using parameters at this point, you specify an empty procedure interface.

Now, you need to go into your existing code and change it so that the procedure is called instead of the subroutine. There are three ways to call a procedure, which may be why some people get confused (too many options), but they're easy to get used to. These are the three ways to call a procedure:

  • Using the CALLB opcode
  • Using the CALLP opcode
  • Implicitly, by specifying the procedure within an expression

For now, you simply want to have a plug-in replacement for the subroutine call, so replace the call to the TOUPPER subroutine with a CALLB to the TOUPPER procedure. Here's the completed code:

C     CustNo        Chain     CustRec
C                   If        %Found()  
C                   move      CSTNAME       TU_WORK
C                   CALLB     'TOUPPER'
C                   move      TU_WORK       Work1

C                   move      OLDNAME       TU_Work
C                   CALLB     'TOUPPER'
C                   move      TU_WORK       Work2
C                   if        Work1 = Work2
 **  Old/New names are identical...
C                   endif
C                   endif

In the example above, the EXSR statements have been replaced with CALLB statements. Note that, in RPG IV, the compiler converts procedure names to uppercase by default. Therefore, when you call a procedure, the procedure name must be in uppercase; otherwise, the compiler will not locate it. If you had specified the CALLB statement like the following, the compile would have failed:

C                   CALLB     'ToUpper'

Now you've created a procedure that can replace the old subroutine, but so what? What advantage does this procedure have over the subroutine call? The answer to this question is simply maintainability.

People say 80% of all programming is maintenance programming. Making changes means working with existing code. If you can reduce the number of lines of code that have to be fiddled around with and isolate those lines of code, you can increase programmer productivity.

For example, suppose you want to avoid using the work fields in these examples. You can easily do that with the TOUPPER procedure without concern for the field names of any other fields (work fields or otherwise) in the program source.

Let's look at a slightly different version of the TOUPPER procedure. This one avoids the use of work fields and instead takes advantage of the parameter capability of procedures.

0001 P ToUpper         B
0002 D ToUpper         PI          1024A   Varying 
0003 D  input                      1024A   Varying CONST

0004 D UPPER           C                   'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
0005 D lower           c                   'abcdefghijklmnopqrstuvwxyz'
0006 D output          S           1024A   Varying
     
0007 C     lower:UPPER   XLate     Input         Output
0008 C                   return    Output
0009 P ToUpper         E

In this updated version of the TOUPPER procedure, I've made the following changes:

  • Added a parameter named INPUT
  • Added a field named OUTPUT
  • Specified a return value for the procedure
  • Moved the named constants UPPER and LOWER to the procedure
  • Returned the OUTPUT field to the caller

To add parameters to procedures, you simply specify the parameter name, its type, and its length, which is virtually identical to declaring a subfield of a data structure. In fact, using procedure parameter lists is very similar to declaring data structures.

In addition, you can specify that the parameter is not going to be changed by the procedure; to do this, add the CONST keyword to the parameter's description (see line 3). Making procedure parameters CONST helps to improve performance when calling the procedure; of course, the downside is that you cannot change the value of CONST parameters from within the procedure.

Return Value

Procedures, like programs, allow you to modify the value of any parameter passed into them (provided, as I mentioned, that the parameter does not contain the CONST keyword). This works essentially the same way that passing parameters to programs works.

Procedures have one more capability, however. Procedures can return a value to the caller without going through a parameter variable. This capability classifies the procedure as a function instead of a procedure, but in RPG IV, we use the term "procedure" generically to mean both procedure and function.

When a procedure is a function, its return value may be used within an expression (a conditional statement or an EVAL operation). For example, since the TOUPPER procedure returns a value, you can use it as follows:

C                   eval      Work1 = TOUPPER(CSTNAME)

Or, better yet, like this:

C                   if        TOUPPER(CSTNAME) = TOUPPER(OLDNAME)

This method not only greatly simplifies the code, but also isolates the original 10-line routine into a single statement.

Let's look at how this TOUPPER procedure would be called compared to the TOUPPER subroutine by rewriting the original code as follows:

C     CustNo        Chain     CustRec
C                   If        %Found()  
C                   if        TOUPPER(CSTNAME) = TOUPPER(OLDNAME)
 **  Old/New names are identical...
C                   endif
C                   endif

This is much cleaner and easier to read and maintain. A maintenance programmer will appreciate all the clutter of those work fields being eliminated.

One Final Component

Procedures, while easier to maintain than other methods do have one confusing element, prototypes. Prototypes are the single biggest source of confusion for RPG IV programmers when they attempt to move to procedures.

Simply put, prototypes are required when using procedures. The compiler uses the prototype source code to syntax check calls made to the procedure to make sure the number of parameters and their data types exactly match what the procedure is expecting.

So in our example, if you specified TOUPPER(12345), you would get a compile-time error message. Try that with a subroutine!

The easiest way to use prototypes is to just accept the fact that the compiler requires them and create them by copying the procedure interface code.

To create a prototype, simply copy the entry parameter list for your procedure, including the PI line and all parameter fields, to another location within the source member. Then, go to the letters "PI" in columns 24 and 25 of that PI line and change them to "PR" (meaning prototype).

Here is the prototype source for the TOUPPER procedure:

0002 D ToUpper         PR          1024A   Varying
0003 D  input                      1024A   Varying CONST

From the source statement sequence numbers, you should be able to tell that I simply copied the procedure interface code from the procedure definition to create this prototype. I then changed the letters "PI" (procedure interface) to "PR" (prototype). This source code must be at the top of the source member with the regular D specifications (above the mainline calcs).

For completeness, I want to illustrate the entire original subroutine method rewritten for procedures:

0001 H DFTACTGRP(*NO) 
0002 FCUSTMAST  UF   E           K DISK    PREFIX('CM.')
0003 FCUSTEDIT  CF   E             WORKSTN

0004 D ToUpper         PR          1024A   Varying
0005 D  input                      1024A   Varying CONST

0006 D CM            E DS                  Extname(CUSTMAST) QUALIFIED
0007 D OLDNAME         S                   Like(CM.CSTNAME) 

0008 C     CustNo        Chain     CustRec
0009 C                   If        %Found()  
0010 C                   if        ToUpper(CM.CSTNAME) = ToUpper(OLDNAME)
      **  Old/New names are identical...
0011 C                   endif
0012 C                   endif


0013 P ToUpper         B
0014 D ToUpper         PI          1024A   Varying
0015 D  input                      1024A   Varying CONST

0016 D UPPER           C                   'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
0017 D lower           c                   'abcdefghijklmnopqrstuvwxyz'
0018 D output          S           1024A   Varying 
     
0019 C     lower:UPPER   XLate     Input         Output
0020 C                   return    Output
0021 P ToUpper         E

In the example above, the field CM.CSTNAME from the customer master file is compared with the field OLDNAME (line 10). The TOUPPER procedure is called twice in one statement, and its return value is what is being compared. Since this procedure uses variable-length fields, the original value's length is also the length of the data that is returned by the procedure.

Just Do It

Procedures are different; they look different and are coded differently. But they are not and should not be scary. Nor should they be avoided. The use of procedures will lead you down a path of easier program maintenance and much greater flexibility than previously available. While you do not need to convert existing subroutines into procedures, you should start writing all new maintained code using procedures whenever the situation calls for a subroutine.

Bob Cozzi is a programmer/consultant, writer/author, and software developer. His popular RPG xTools add-on subprocedure library for RPG IV is fast becoming a standard with RPG developers. His book The Modern RPG Language has been the most widely used RPG programming book for more than a decade. He, along with others, speaks at and produces the highly popular RPG World conference for RPG programmers.

BOB COZZI

Bob Cozzi is a programmer/consultant, writer/author, and software developer. His popular RPG xTools add-on subprocedure library for RPG IV is fast becoming a standard with RPG developers. His book The Modern RPG Language has been the most widely used RPG programming book for more than a decade. He, along with others, speaks at and produces the highly popular RPG World conference for RPG programmers.


MC Press books written by Robert Cozzi available now on the MC Press Bookstore.

RPG TnT RPG TnT
Get this jam-packed resource of quick, easy-to-implement RPG tips!
List Price $65.00

Now On Sale

The Modern RPG IV Language The Modern RPG IV Language
Cozzi on everything RPG! What more could you want?
List Price $99.95

Now On Sale

BLOG COMMENTS POWERED BY DISQUS

LATEST COMMENTS

Support MC Press Online

$

Book Reviews

Resource Center

  • SB Profound WC 5536 Have you been wondering about Node.js? Our free Node.js Webinar Series takes you from total beginner to creating a fully-functional IBM i Node.js business application. You can find Part 1 here. In Part 2 of our free Node.js Webinar Series, Brian May teaches you the different tooling options available for writing code, debugging, and using Git for version control. Brian will briefly discuss the different tools available, and demonstrate his preferred setup for Node development on IBM i or any platform. Attend this webinar to learn:

  • SB Profound WP 5539More than ever, there is a demand for IT to deliver innovation. Your IBM i has been an essential part of your business operations for years. However, your organization may struggle to maintain the current system and implement new projects. The thousands of customers we've worked with and surveyed state that expectations regarding the digital footprint and vision of the company are not aligned with the current IT environment.

  • SB HelpSystems ROBOT Generic IBM announced the E1080 servers using the latest Power10 processor in September 2021. The most powerful processor from IBM to date, Power10 is designed to handle the demands of doing business in today’s high-tech atmosphere, including running cloud applications, supporting big data, and managing AI workloads. But what does Power10 mean for your data center? In this recorded webinar, IBMers Dan Sundt and Dylan Boday join IBM Power Champion Tom Huntington for a discussion on why Power10 technology is the right strategic investment if you run IBM i, AIX, or Linux. In this action-packed hour, Tom will share trends from the IBM i and AIX user communities while Dan and Dylan dive into the tech specs for key hardware, including:

  • Magic MarkTRY the one package that solves all your document design and printing challenges on all your platforms. Produce bar code labels, electronic forms, ad hoc reports, and RFID tags – without programming! MarkMagic is the only document design and print solution that combines report writing, WYSIWYG label and forms design, and conditional printing in one integrated product. Make sure your data survives when catastrophe hits. Request your trial now!  Request Now.

  • SB HelpSystems ROBOT GenericForms of ransomware has been around for over 30 years, and with more and more organizations suffering attacks each year, it continues to endure. What has made ransomware such a durable threat and what is the best way to combat it? In order to prevent ransomware, organizations must first understand how it works.

  • SB HelpSystems ROBOT GenericIT security is a top priority for businesses around the world, but most IBM i pros don’t know where to begin—and most cybersecurity experts don’t know IBM i. In this session, Robin Tatam explores the business impact of lax IBM i security, the top vulnerabilities putting IBM i at risk, and the steps you can take to protect your organization. If you’re looking to avoid unexpected downtime or corrupted data, you don’t want to miss this session.

  • SB HelpSystems ROBOT GenericCan you trust all of your users all of the time? A typical end user receives 16 malicious emails each month, but only 17 percent of these phishing campaigns are reported to IT. Once an attack is underway, most organizations won’t discover the breach until six months later. A staggering amount of damage can occur in that time. Despite these risks, 93 percent of organizations are leaving their IBM i systems vulnerable to cybercrime. In this on-demand webinar, IBM i security experts Robin Tatam and Sandi Moore will reveal:

  • FORTRA Disaster protection is vital to every business. Yet, it often consists of patched together procedures that are prone to error. From automatic backups to data encryption to media management, Robot automates the routine (yet often complex) tasks of iSeries backup and recovery, saving you time and money and making the process safer and more reliable. Automate your backups with the Robot Backup and Recovery Solution. Key features include:

  • FORTRAManaging messages on your IBM i can be more than a full-time job if you have to do it manually. Messages need a response and resources must be monitored—often over multiple systems and across platforms. How can you be sure you won’t miss important system events? Automate your message center with the Robot Message Management Solution. Key features include:

  • FORTRAThe thought of printing, distributing, and storing iSeries reports manually may reduce you to tears. Paper and labor costs associated with report generation can spiral out of control. Mountains of paper threaten to swamp your files. Robot automates report bursting, distribution, bundling, and archiving, and offers secure, selective online report viewing. Manage your reports with the Robot Report Management Solution. Key features include:

  • FORTRAFor over 30 years, Robot has been a leader in systems management for IBM i. With batch job creation and scheduling at its core, the Robot Job Scheduling Solution reduces the opportunity for human error and helps you maintain service levels, automating even the biggest, most complex runbooks. Manage your job schedule with the Robot Job Scheduling Solution. Key features include:

  • LANSA Business users want new applications now. Market and regulatory pressures require faster application updates and delivery into production. Your IBM i developers may be approaching retirement, and you see no sure way to fill their positions with experienced developers. In addition, you may be caught between maintaining your existing applications and the uncertainty of moving to something new.

  • LANSAWhen it comes to creating your business applications, there are hundreds of coding platforms and programming languages to choose from. These options range from very complex traditional programming languages to Low-Code platforms where sometimes no traditional coding experience is needed. Download our whitepaper, The Power of Writing Code in a Low-Code Solution, and:

  • LANSASupply Chain is becoming increasingly complex and unpredictable. From raw materials for manufacturing to food supply chains, the journey from source to production to delivery to consumers is marred with inefficiencies, manual processes, shortages, recalls, counterfeits, and scandals. In this webinar, we discuss how:

  • The MC Resource Centers bring you the widest selection of white papers, trial software, and on-demand webcasts for you to choose from. >> Review the list of White Papers, Trial Software or On-Demand Webcast at the MC Press Resource Center. >> Add the items to yru Cart and complet he checkout process and submit

  • Profound Logic Have you been wondering about Node.js? Our free Node.js Webinar Series takes you from total beginner to creating a fully-functional IBM i Node.js business application.

  • SB Profound WC 5536Join us for this hour-long webcast that will explore:

  • Fortra IT managers hoping to find new IBM i talent are discovering that the pool of experienced RPG programmers and operators or administrators with intimate knowledge of the operating system and the applications that run on it is small. This begs the question: How will you manage the platform that supports such a big part of your business? This guide offers strategies and software suggestions to help you plan IT staffing and resources and smooth the transition after your AS/400 talent retires. Read on to learn: