Guild Companies, Inc.  
 
Midrange Programmer - How-To Advice & Free Code
OS/400 Edition
Volume 1, Number 6 - March 28, 2002

Recursive Calls Using Subprocedures

by Kevin Vandever

[The code for this article is available for download.]

In "Subprocedures: Better than Subroutines," Ted Holt discusses the advantages of subprocedures over subroutines, and talks about local variables, return values, and the different ways to define parameters when using subprocedures. One advantage he mentions--but leaves for another article--is that subprocedures support recursion. Well, this is that article. I'm going to discuss the basics of recursion and provide an example of when you might want to use it in your applications.

Why Would I Call Myself?

A recursive call is generated when a subprocedure calls itself. You cannot accomplish this in any other way using RPG. For instance, you cannot call PROGRAMA from within PROGRAMA. Nor can you call PROGRAMA, which calls PROGRAMB, which then again calls PROGRAMA. These are no-no's and a nasty run-time error or, worse, an angry user will tell you so. The same holds true for subroutines. You cannot call a subroutine from within itself. The good news here is that the compiler won't even let you code a subroutine that calls itself. Big deal, right? Subprocedures support recursion. So when is the right time to use recursion? How about if you needed to calculate factorials? You know, 5 factorial (5!) is 5x4x3x2x1, or 120. Computing factorials may be fine for a programming assignment in school, but you are probably interested in a real-life business reason to employ recursive calls. The best time to take advantage of recursion is when your data is stored in a hierarchical level as opposed to the relational level to which we are accustomed. In a relational database, you have a parent-child relationship. That is, you have a master file in a one-to-many relationship with detail records contained in a detail file. RPG programmers are adept at displaying or printing information stored in a relational database structure. A hierarchical structure (also known as a recursive structure) does not have this parent-child relationship. In this hierarchical structure, the data is independent of the rest of the data while also possibly being associated with it.

The Food Chain

A kit/component structure is a prime example of hierarchical data. A kit, or part, can be the finished product or a component to another kit. Or it could be both. A company's chain of command is another example of a hierarchical structure. A person may be a manager or supervisor of other managers and supervisors. That means a person may be listed in the hierarchy as both manager and subordinate. In using a relational database system, it would be difficult to list the chain of command. It wouldn't be too bad to find out who reports to a specific person, but it becomes a bit more complex when you want to find out who reports to the person who reports to the first person, and so on. If the data is stored in a recursive fashion, it makes sense that the programmer would employ a recursive method to display it. Let's take a look at how this concept works.

In my example, I'm going to pass in to my program an employee's ID number and then list the chain of command using recursive calls to a subfile load subprocedure. I will mark each new level of command by indenting the names. The following figure contains the output from running my program and shows that Shannon, Ted, and Jim are direct reports to me. It also shows that Shannon has three direct reports, Tim, Felicia, and Kalia, while Ted and Jim each have one direct report, Joe and Goofy respectively.

Simple Subfile Stuff

ORGLISTDF is the DDS that defines a typical load-all subfile. The only interesting thing to note here is the 60-byte field, SUBNAM, listed in the subfile record format. A field of this size allows me to concatenate the first and last name of the employee and indent that name to the appropriate level within the chain of command. By using one long field name, I am able to indent the name a little more to the right for each level in the chain, without knowing how many levels actually exist. In my example, you are limited in the number of levels you can display by the number of positions on the screen--you can indent only so far to the right, correct? However, you could add a field to the subfile to contain one's level down the food chain and not have to worry about concatenating the names and indenting them, but I chose to indent the names to further illustrate the effect of recursive calls.

The RPG Mainline

Let's take a look at the RPG program, ORGLIST. I am using two data files in this example: an employee master file, EMPMST, and a hierarchical subordinate file, EMPSUB. The subordinate file will contain two fields per record: the employee ID and a subordinate ID. I am going to be using one subfile to display the records and will load one level of command per call to the subprocedure. In my example, there are only two levels under me; therefore, only two recursive calls to the subprocedure are listed. Refer to Ted's article for a complete explanation of subprocedures and how they are coded. I am going to concentrate on recursion in this article and assume you are comfortable with subprocedures. The mainline routine accepts the employee ID from the user who is calling the program. It then gets the name associated with that ID and formats it for display in the heading. If the employee ID is not found, I state so in the NAME field and display the screen. If the ID is found, I am now ready to start building my subfile. First, I execute the CLRSFL routine, which, you guessed it, clears my subfile. Then, I call the NextLevel subprocedure using the CALLP operation. I pass the level, which is one the first time through, and the employee ID that was passed in by the user. This one call to the NextLevel subprocedure will start the recursive process and build the subfile. When control is returned back to the mainline routine after this call to the NextLevelLevel subprocedure, the subfile is ready to be displayed. After the call to the subprocedure, I set on my SFLEND indicator, *IN90, check to see if any records were written to the subfile, and execute the Do Until (DoU) loop to display the subfile.

The Meat

Now the fun begins. Inside my subprocedure, I define a local variable, SAVSUBORD, to hold the current subordinate ID for the specific call level of the subprocedure. (Yep, this is RPG and I mentioned local variables without having to size myself for a straitjacket.) Any variables you define inside the subprocedure are only available within the subprocedure. In my example, I define a variable to save the subordinate number for return from recursive calls. Oh yeah, any local variables that are defined are local to the specific running of a subprocedure. Any subsequent calls to the same subprocedure (that would be recursion) will create new local variables scoped to that instance of the subprocedure. The way the subfile is built is that each recursive call to a subprocedure will represent a new level in the chain of command. If you take a look at the structure of my subprocedure, it is built around a Do While (DoW) loop that will find all the subordinates for the employee ID passed as a parameter to the subprocedure. After the record is found, it is formatted and written to the subfile. After each successful write to the subfile within the DoW loop, the NextLevel procedure is called again, passing the current level plus one and the subordinate's ID that was obtained with the previous read to EMPSUB. This will allow me to find out if the current subordinate (for example, Shannon) has any subordinate entries in the file before reading the next record for the current employee (Kevin). Are you with me so far? Only when I return from previous calls to the NextLevel subprocedure will I set the pointer using the SavSubord field and read the file again for the current employee. What happened in the meantime is that the NextLevel subprocedure was called as many times as it was needed to drill down to the lowest level in the chain of command. As each level was satisfied, the previous level was allowed to finish until you get back to the first instance of NextLevel, in which case, the whole process starts over again. Take a moment to absorb this information.

One Step at a Time

This may seem a little confusing at first, but if you look at one instance of subprocedure at a time and realize that it is building the subfile for one level of the org chart, you can then start to understand how each subsequent call works. One thing to remember is that you can get yourself in trouble if you don't watch what you're doing. In my example, there is a definite end to my logic; that is, when the last level in the subordinate file is read. Make sure you understand what you're doing. You don't want to get into the situation where you have never-ending recursion. That is a bad thing as each recursive call creates another level in the call stack, so it not only goes on forever, but it sucks up memory in the process. But other than that, recursion is fun, safe, and a very effective way to process hierarchical data.

Sponsored By
CLIENT SERVER DEVELOPMENT

LEARN SQL FROM
THE SQL EXPERT

Howard F. Arner, Jr.

Buy your copy of iSeries and AS/400 SQL at Work direct from the author, Howard F. Arner, Jr. This is THE book to teach you SQL on the iSeries and AS/400 platform.

Howard takes you from the beginning of the book to the end with information that is useful for beginners and experts alike. The book comes with a CD that has all of the sample data and queries used in the book and a FREE copy of SQLThing that you can use to work through the examples in the book, so you learn by doing.

With Howard's expert guidance, you'll learn and understand many topics, including the following:

  • Relational Concepts and Terms
  • SQL Select Basics
  • Manipulating Data in SQL Tables
  • Advanced Select Statements
  • Cursors, Transactions, Journals, and Logging
  • Debugging SQL Statements and Enhancing Performance
  • Stored Procedures
  • Embedded SQL in RPG

Howard F. Arner, Jr., is a programmer who has published extensively on integration of AS/400 legacy systems. In his book, iSeries and AS/400 SQL at Work, Howard provides detailed coverage of SQL for business environments by using practical examples--available on the CD--to be performed by the reader. More advanced chapters teach how to become proficient in industry-standard SQL to manipulate AS/400 data, use scalar functions to summarize data, and make legacy RPG and COBOL programs AS/400-compatible. This is the perfect guide for beginners and advanced SQL users.

Here's what readers are saying about iSeries and AS/400 SQL at Work by Howard F. Arner:

Anyone working with AS/400 query should look into buying this book. Now using AS/400 query seems a little odd and very cumbersome. His writing is laid out very well and is easy to read. While reading this, I felt that he was actually there explaining the chapters to me as a one-on-one instructor. -- Jonathan Tripp, Deerfield Beach, Florida

If you wondered how to call AS/400 programs from your Visual Basic program correctly, this book is your one source for how to do so. It's the first book on the market that answered all of my client/server questions when I deal with PC to AS/400 programming tasks.

Not only does Howard do a good job of explaining how stored procedures work, but he gives some great coding examples on how to get you up and running correctly. Howard goes the extra mile and talks about performance, too--one thing that normally is lacking in many other books. -- Bob Butcher, Sidney, New York

Take your knowledge and understanding of SQL to the next level. Order your copy at SQLThing.com.

THIS ISSUE
SPONSORED BY:
BCD Int'l
Client Server Dev.
COMMON
SoftLanding Systems
Profound Logic Software
Midrange Blue Book
BACK ISSUES
TABLE OF CONTENTS
Form Up to Learn About HTML Forms
Recursive Calls Using Subprocedures
Getting Started with XML
Working with Parameters and Variables in Qshell Scripts
Test Data Queue Applications Using Java
CODE/400's Code/Editor: Tips and Tricks
  Newsletters | Subscribe | Advertise | About Us | Contact | Search | Home  
  Last Updated: 3/27/02
Copyright © 1996-2008 Guild Companies, Inc. All Rights Reserved.