24
Tue, Dec
1 New Articles

Practical RPG: Increase Productivity with Parameters and Return Values

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

The real power of procedures is revealed in this article through the use of parameters and return values.

 

This is the last article in this series on Prototyping for Productivity. This is where I finally put all the pieces together and remove a third of the code in my little sample program. More impressive, though, is that, through the magic of D-specs, I turn 13 executable lines of code into four. While there just wasn't much code in this particular program to remove, in a real production application, the amount of code removed can be significant. Not only that, it's the type of repetitive code (validation, formatting, etc.) that is naturally prone to typographic errors—the kind that compile but cause errors.

Letting Parameters Do the Work

As I said, this article is the fourth in a series of articles. The first article showed you how to use a prototype to replace the PLIST in your programs, and the second article explained how to replace a subroutine with a subprocedure. The third article took a side trip to do a little investigation of the variable-length fields using the VARYING keyword. In this last installment, I'll show you how a couple of simple keywords can allow you to really take advantage of subprocedures to reduce your code.

Meet the Old Program

As I like to do in this series, let me reacquaint you to our program as we left it:

 

A h option(*srcstmt: *nodebugio) dftactgrp(*no) actgrp(*new) 

                                                             

B d ShowData        pr                  extpgm('PRO1SND')    

B d   Data                       512a                        

                                                            

C d TagThis         pr                                        

C d   Tag                         10a   varying              

C d   Value                       80a   varying              

C d   TaggedValue                128a   varying              

                                                             

D d aTag            s             10a   varying              

D d aValue          s             80a   varying              

D d aTaggedValue    s            128a   varying              

                                                             

E d aBuffer         s            512a   varying              

E d OutBuffer       s            512a                        

                                                            

   /free                                                      

                                                            

F   aTag = 'FIELD1';                                         

F   aValue = 'Field 1 Value';                                

F   TagThis( aTag: aValue: aTaggedValue);                     

F   aBuffer = aTaggedValue;                                  

                                                            

G   aTag = 'FIELD2';                                         

G   aValue = 'Field 2 Value';                                 

G   TagThis( aTag: aValue: aTaggedValue);                    

G   aBuffer += aTaggedValue;                                 

                                                            

H   OutBuffer = aBuffer;                                     

H   ShowData( OutBuffer);                                    

H   *inlr = *on;                                             

   /end-free                                                 

                                                            

I p TagThis         b                                        

I d                 pi                                       

I d   Tag                         10a   varying              

I d   Value                       80a   varying              

I d   TaggedValue                128a   varying              

I  /free                                                     

I   TaggedValue = '<' + Tag + '>' + Value + '</' + Tag + '>';

I  /end-free                                                 

I p                 e                                        

 

A: My standard header specification for ILE programs.

 

B: A prototype for the PRO1SND program (this sends the value to the user in a message).

 

C: This is the internal prototype for the TagThis subprocedure. This formally declares the parameters that will be passed.

 

D and E: My temporary variables, most of which are variable-length fields. The first three are used to communicate with the TagThis subprocedure, and aBuffer is my work buffer. OutBuffer is my only fixed-length field and is used to send the data to PRO1SND.

 

F and G: These are the calls to TagThis. I pass the tag and value to TagThis, and it creates a tagged value. I concatenate those together into aBuffer.

 

H: ShowData calls the program PRO1SND, and since PRO1SND is a traditional program using fixed-length fields, I have to convert the variable-length field to a fixed-length field before I call. I assign aBuffer to OutBuffer and RPG automatically pads the field with blanks. I then pass the fixed-length field to the called program and exit the program.

 

I: TagThis creates the tagged value. Thanks to the wonders of variable-length fields, it requires only a single executable line of code to take the first two fields and create a tagged value of the format <TAG>VALUE</TAG>.

 

Simple program and relatively efficient. But now it's time to really squeeze it.

The Many Uses of CONST

The first of two modifications is the strategic addition of the CONST keyword. CONST is a keyword that modifies how a parameter works and has two very different but equally powerful capabilities. Like VARYING, these capabilities are useful in either ILE or non-ILE environments, because you can use prototypes to call external programs as well as procedures. I'll show you both situations in this example.

 

When you specify CONST on a parameter definition, the high-level effect is that the compiler makes the parameter read-only. You can think of the compiler as making a copy of your parameter before passing it to the called program or procedure. This has a number of side effects, two of which can be very advantageous. The first positive benefit is that the compiler will do conversions for you. It will, for example, convert a packed value into a signed value, or more importantly to this example, it will convert a variable-length field into a fixed-length field. The second benefit is sort of a corollary to the first: you can pass a literal to a program or procedure. That is, you can specify a literal value, either a named constant or even a literal, right in the call.

 

Together, these two capabilities remove a lot of code by removing the need for internal working variables. This is the new version:

 

A h option(*srcstmt: *nodebugio) dftactgrp(*no) actgrp(*new)

 

B d ShowData        pr                  extpgm('PRO1SND')

B d   Data                       512a   const

 

C d TagThis         pr

C d   Tag                         10a   varying const

C d   Value                       80a   varying const

C d   TaggedValue                128a   varying

 

D d aTaggedValue    s            128a   varying

 

E d aBuffer         s            512a   varying

 

  /free

 

F   TagThis( 'FIELD1': 'Field 1 Value': aTaggedValue);

F   aBuffer = aTaggedValue;

 

G   TagThis( 'FIELD2': 'Field 2 Value': aTaggedValue);

G   aBuffer += aTaggedValue;

 

H   ShowData( aBuffer);

H   *inlr = *on;

  /end-free

 

I p TagThis         b

I d                 pi

I d   Tag                         10a   varying const

I d   Value                       80a   varying const

I d   TaggedValue                128a   varying

I  /free

I   TaggedValue = '<' + Tag + '>' + Value + '</' + Tag + '>';

I  /end-free

I p                 e

 

A: This doesn't change.

 

B and C: The prototypes for both of these use the CONST keyword on the parameters. In the case of TagThis, the third parameter is not marked as CONST because we need it to return the modified value to the caller.

 

D: Only one temporary variable. The changes in F and G remove the need for the others.

 

E: Only one interface variable. Because I've defined the parameter to ShowData as constant, I don't need a fixed-length interface variable.

 

F and G: Now we start actually removing lines of code (and variables!). I don't need to set aTag and aValue to literal values and then pass them to the formatting routine. Instead, I can specify those literals right on the call.

 

H: Another line of code disappears because I can pass the variable-length field directly on the call, and the compiler will convert it to a fixed-length field for me.

 

I: No changes here.

 

Can you see how this simplifies the code?  And while the example is trivial, the technique has real power. For instance, I can pass an expression. For character values, I can use BIFs like %trim and %replace, and for numeric values, I can write calculations, all on the call. No work variables (and the associated problems of keeping them sized correctly).

The Last Step: Return Values

It's time to put the icing on the cake. I still have a work variable, aTaggedValue, that I have to pass back and forth between routines. It's not horrible, but it does require an extra field and it's one more place where I can forget to change a length. A better way to handle this is through the use of a return value.

 

A h option(*srcstmt: *nodebugio) dftactgrp(*no) actgrp(*new)

                                                            

B d ShowData        pr                  extpgm('PRO1SND')   

B d   Data                       512a   const               

                                                             

C d TagThis         pr           128a   varying             

C d   Tag                         10a   varying const       

C d   Value                       80a   varying const       

                                                             

E d aBuffer         s            512a   varying             

                                                            

   /free                                                    

F   aBuffer =                                                

F     TagThis( 'FIELD1': 'Field 1 Value') +                 

G     TagThis( 'FIELD2': 'Field 2 Value');                  

                                                            

H   ShowData( aBuffer);                                     

H   *inlr = *on;                                            

   /end-free                                                

                                                            

I p TagThis         b                                       

I d                 pi           128a   varying             

I d   Tag                         10a   varying const       

I d   Value                       80a   varying const       

I  /free                                                    

I   return '<' + Tag + '>' + Value + '</' + Tag + '>';      

I  /end-free                                                

I p                 e                                       

 

This is the coup de grace! Let' review the changes.

 

A and B: No changes.

 

C: The TagThis prototype is different. The third parameter has been removed, and the prototype definition (the first line, with the "pr") has been changed to indicate that TagThis returns a 128-character variable-length field. So now, rather than updating a parameter, TagThis returns the result.

 

Section D is gone; we no longer need the variable aTaggedValue at all.

 

E: Doesn't change.

 

F and G:  This is the real change to the programming. Because TagThis now returns a value, the calls to TagThis can be included on the right side of an assignment operation. Instead of having to write individual calls to set work variables and then using those work variables, I can set aBuffer to the result of the first call concatenated to the result of the second call, all in one line.

 

H: No change.

 

I: This is the other half of the programming change. The procedure interface (the line with the "pi") is modified in a way that mirrors the changes in C. The third parameter is removed; instead, the subprocedure will return a value. And rather than setting the contents of a parameter to the formatted result, the subprocedure instead uses the return opcode to return the value to the caller.

 

That's it. If you go all the way back to the original program, you'll find that we've removed most of the working variables and two-thirds of the executable code. That's the strength of procedures and one of the reasons that ILE RPG deserves a place among the modern programming languages of today's application development world.

 

This isn't perfect. Return values can be used only on subprocedures (either internal or external), not on calls to programs. Also, prior to 7.1, a field returned from a subprocedure is treated as a "by copy" field, meaning that the subprocedure uses an internal copy of the variable, which is then copied to the caller's variable when the procedure returns. This is a potential performance issue on large return values, but the RPG compiler team fixed that with a keyword (RTNPARM) that turns it into a pass by reference. I also still have one working variable; I'll leave it as an exercise for you to identify how to remove that last field.

Parameters Are Your Friends

I hope this article has shown you the benefits of using parameters and return values and the ways some of their keywords can reduce your programming load. I also hope the whole series has given you a reason to start using prototypes (especially for subprocedures). I know this is a trivial program; it was designed specifically just to show you the features. In another series of articles, I'd like to present some examples of using these capabilities to address real-world programming issues. Until then, good luck with prototypes!

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: