RPG Subprocedure Tips and Techniques

  • Home
  • /
  • Blog
  • /
  • RPG Subprocedure Tips and Techniques

September 15, 2013

If you have not jumped on the subprocedure bandwagon yet, put it right at the top of your to-do list for this year.

You do not have to drop everything and rewrite every old program on your IBM i to grab the benefits of subprocedures and the rest of the ILE goodness. That would be madness. But when you are writing new code or doing any serious refresh on existing components, you really should reach for these powerful, yet still under-used, tools.

At first glance subprocedures look pretty simple. If your applications already have a touch of modularity, either through external program calls or subprocedures that keep the mainline code clean and readable, then subprocedures just feel right.

Before you leap into your first big project that uses subprocedures (maybe through modules or service programs), it is worth picking up a few important lessons and handy tricks from the folks who use ILE every single day.

programmer

Subprocedures should have one function and one function only

If you have spent years writing classic RPG with subroutines, you may have developed the (slightly frowned-upon) habit of stuffing way too much logic into a single subroutine. We have all been there.

When you write ILE subprocedures, the golden rule is to make each one do exactly one thing. That single focus is what gives you the biggest payback.

Suppose you create a subprocedure called #updateSales. It checks the sales details for a customer when an invoice is created, then updates the customer sales totals and the associated accounts-receivable records. Nice and tidy, right?

Later you are working on an AR adjustment program and realise that half the work you need is already sitting inside #updateSales. In a hurry you might copy the whole thing into a new #updateAR subprocedure. Problem solved, until the next time you need to change the logic in one place but not the other.

Suddenly your clever time-saver has become a maintenance headache. If you find yourself describing what a subprocedure does with a sentence that contains “and” or “or”, you have found your clue. Split it.

In the example above you should have created #updateCustSales and #updateAR as separate subprocedures. Each does one job and can be called on its own or together. You can still keep an #updateSales wrapper that simply calls both, but that wrapper should do nothing else. Clean, reusable, and future-proof. Your future self will thank you, probably with coffee.

Subprocedure parameters: by reference or by value

Before ILE we had no real choice about how parameters were passed. Now we do, and the decision matters.

When you define a parameter in a prototype or procedure interface without any keyword, it is passed by reference. Only the memory address travels across. The called subprocedure works directly on the original variable, so changes come straight back to the caller. Handy when you want the subprocedure to update something for you.

Add the CONST keyword and you still pass by reference, but the subprocedure is not allowed to change the value. Two bonuses here: you can safely pass literal values, and you can pass variables that are different lengths from the prototype definition. Passing a 100-character string into a 200-character parameter becomes completely legal. No more padding nonsense.

Use the VALUE keyword and the subprocedure gets its own fresh copy in memory. Tweak it as much as you like inside the subprocedure; the caller’s variable stays untouched.

One quick gotcha for the CL fans among us: CL programs cannot pass parameters by value, so VALUE will not work when you call from CL.

My rule of thumb? If the parameter is not coming back changed to the caller, slap CONST on it. It stops accidental modifications and makes the code safer and more flexible. Less debugging, more getting things done.

Understanding the scope of variables

One of the best things about subprocedures is local variables. For most of us who grew up on pure RPG, every variable used to be global. That was fine until your loop counter “i” got overwritten somewhere else in the program and you spent three hours chasing a ghost.

Local variables live only inside their subprocedure. Define the same counter “i” in two different subprocedures and they are completely independent. No more mystery bugs at 2 a.m. That alone is worth the price of admission.

Until IBM i V5R2, file-based fields (from database or display files) were always global. You can now get around that by defining a data structure locally with the LIKEREC keyword (not EXTNAME) and reading records straight into it. The record lands in a nice tidy local structure instead of polluting the global namespace.

Even if your subprocedures live inside the same main program, using local variables removes a whole class of silly errors. Small win, big smile.

Pointers as parameters

Pointers can be useful, but they are not always the hero you think they are.

If you pass a large string by VALUE, a pointer might give you a tiny performance edge. Most of the time, though, parameters are already passed by reference, so you gain nothing by adding an extra pointer layer.

Never return a pointer to a local variable inside the subprocedure. That storage gets reclaimed as soon as the subprocedure ends, and your program will have a very bad day when it tries to use it later. Global or static variables are safer, but only if everything stays in the same activation group.

With all the modern RPG compiler enhancements, you rarely need pointers for parameters any more. When you do reach for them, double-check you are not quietly planting a time bomb.

Parameter options

The OPTIONS keyword on your parameter definitions opens up some neat extra behaviour. You define it like this:

D Variable nn OPTIONS(option_value)

Here are the ones you will use most:

  • *VARSIZE lets you pass variables shorter than the prototype definition. Just remember you need a way to know how much data actually arrived, usually by passing a length or using operational descriptors.
  • *NOPASS marks a parameter as optional. Every parameter after it must also be *NOPASS. Check %PARMS inside the subprocedure so you know what you actually received.
  • *OMIT lets you pass the special *OMIT value for reference parameters. Useful when you have optional parameters but later ones are required.
  • *STRING tells the compiler to accept a character string and quietly turn it into a null-terminated C-style string for you. Perfect when you are calling system APIs that expect pointers to null-terminated strings.
  • *RIGHTADJ automatically right-adjusts the value for parameters defined with VALUE or CONST. It does not work with varying-length fields, but it is great for fixed-length ones.

Some of these options depend on your IBM i release, so always check the docs for your version. Understanding what each one actually does keeps your code clean and prevents those “why is this blowing up?” moments.

Knowing the tools in your RPG toolbox is the first step toward building applications that are easier to maintain, easier to reuse, and genuinely fun to work on. Subprocedures are one of the best tools we have on IBM i. Use them wisely and your code will thank you every single day.

Need more techie detail direct from IBM’s mouth?

Start with the IBM Manual — sc092508 – Programming IBM Rational Development Studio for I ILE RPG Reference

RPG Programming for Beginners

RPG is the well known programming language on the IBM i platform. Earlier versions of RPG ran on the old AS/400 and iSeries machines in decades gone by… the beauty of RPG is that it is fully backwards compatible. Over the years RPG has evolved massively and now looks like a completely different language. Dive into this course to learn the basics, review old column based RPG, and modernize samples right up to modern RPGLE and SQLRPGLE code standards.

NickLitten


IBM i Software Developer, Digital Dad, AS400 Anarchist, RPG Modernizer, Shameless Trekkie, Belligerent Nerd, Englishman Abroad and Passionate Eater of Cheese and Biscuits.

Nick Litten Dot Com is a mixture of blog posts that can be sometimes serious, frequently playful and probably down-right pointless all in the space of a day.

Enjoy your stay, feel free to comment and remember: If at first you don't succeed then skydiving probably isn't a hobby you should look into.

Nick Litten

related posts:

{"email":"Email address invalid","url":"Website address invalid","required":"Required field missing"}

Subscribe NOW
7-day free trial

Take This Course with ALL ACCESS

Unlock your Learning Potential with instant access to every course and all new courses as they are released.
 [ For Serious Software Developers only ]

Online Learning for IBM i Software Technology Professionals

“The more that you read, the more things you will know. The more that you learn, the more places you’ll go.” – Dr. Seuss

>