Returning Multiple Values from a Subprocedure

An attendee at one of our recent presentations posed a question about subprocedures. Because questions of this nature frequently arise, we thought that we'd make it the focus of this month's article. The question was, "I'm trying to write a procedure that returns a set of records. When the subprocedure returns to the main program, the value in one of the fields is correct but the others contain garbage. What am I doing wrong? Is there another way to accomplish this?"

If you examine the program listing below, you'll see that the users approach was to build an array in the subprocedure and then return a pointer to the array. This, in turn, was used to base the callers copy of the array. This approach doesn't work because of the way in which storage is allocated in subprocedures. The pointer being returned is defined locally in the subprocedure. Therefore, both it and the storage it references are automatic.

This highlights one of the major differences in storage allocation between subprocedures and conventional RPG programs. In a conventional program, all storage is static, which means it's allocated when the program is first called and remains allocated until the program sets on LR (or the activation group goes away). In subprocedures, on the other hand, storage is allocated when the subprocedure is called and it's released when the subprocedure returns. The result is that although a valid pointer was successfully returned, the storage it points to had been released. The fact that any of the fields contained correct information was coincidence and probably due to the storage having not yet been reused.

You can take various approaches to resolve this. The simplest, and perhaps most obvious, is to add the STATIC keyword to the definition of InvoiceArray. This causes the storage to be defined as static (the same type of storage as a regular RPG program). This fixes the immediate problem, but it isn't the approach wed recommend, primarily because the subprocedure has no way of invalidating the pointer it returned to the caller. Why does this matter? Suppose the application is modified such that the subprocedure is called from a different point in the application. The new caller receives a pointer to the data array; however, from the original caller's perspective, the array content just changed and it has no way of knowing this happened. If control returns to the original caller, it continues to use the array without realizing that it no longer contains the correct information. While this may be an unlikely occurrence, it's a dangerous precedent to establish.

Another approach is to use the Export and Import keywords. The array is defined in the subprocedure with the Export keyword and defined with Import in any program that uses the subprocedure. Although this is technically a different solution, it presents the same problem. The fact that the arrays content changes as a result of the operation isn't obvious, and we still have the same problem with multiple callers.

A better alternative might be to have the caller "own" the array and pass it to the subprocedure as an additional parameter. We've been doing this for years with regular program calls because we lacked the ability to return a value directly. In this case we can have the subprocedure not only fill the array, but also return a count of the number of entries loaded -- or zero if none is found. Certainly this is a useful extension to the function.


Jon Paris is a technical editor with IBM Systems Magazine and co-owner of Partner400.

Susan Gantner is a technical editor with IBM Systems Magazine and co-owner of Partner400.

comments powered by Disqus



2019 Solutions Edition

A Comprehensive Online Buyer's Guide to Solutions, Services and Education.

New and Improved XML-INTO

Namespace support makes the opcode a viable option

Authenticating on the Web

The finer points of OpenRPGUI, Part 1

The Microphone is Open

Add your voice: Should IBM i include open-source RPG tools?

IBM Systems Magazine Subscribe Box Read Now Link Subscribe Now Link iPad App Google Play Store
IBMi News Sign Up Today! Past News Letters