The RTNPARM keyword specifies that the return value of a procedure is to be handled internally as a parameter of the same type as the defined returned value, passed by reference.
Using RTNPARM may improve performance when returning large values.
The impact on performance due to the RTNPARM keyword will vary from having a small negative impact to having a large positive impact. There may be a small negative impact when the prototyped return value is relatively small, such as an integer, or a small data structure. There will be some improvement when the prototyped return value is a larger value such as a 32767 byte data structure. The performance improvement is most apparent when the prototyped return value is a large varying length string, and the actual returned value is relatively small; for example, the prototype defines the return value as a one million byte varying length character string, and the value 'abc' is returned.
Using RTNPARM for a procedure prototype may also reduce the amount of automatic storage required for other procedures that contain calls to that procedure. For example, if procedure MYCALLER contains a call to procedure MYPROC that returns a large value, procedure MYCALLER will require additional automatic storage (even if MYCALLER does not actually call procedure MYPROC at run time). In some cases, procedure MYCALLER will not compile due to excessive automatic storage requirements; in other cases, MYCALLER is not able to be called because the total automatic storage on the call stack would exceed the maximum. Using RTNPARM avoids this problem with additional automatic storage.
The RTNPARM keyword applies both to a prototype definition and to a procedure-interface definition.
1. The prototype for the procedure
D center pr 100000a varying
D rtnparm
D text 50000a const varying
D len 10i 0 value
2. Calling the procedure
D title s 100a varying
/free
title = center ('Chapter 1' : 20);
// title = ' Chapter 1 '
3.The procedure
P center b export
D center pi 100000a varying
D rtnparm
D text 50000a const varying
D len 10i 0 value
D blanks s 50000a inz(*blanks)
D numBlanks s 10i 0
D startBlanks s 10i 0
D endBlanks s 10i 0
/free
if len < %len(text);
... handle invalid input
endif;
numBlanks = len - %len(text);
startBlanks = numBlanks / 2;
endBlanks = numBlanks - startBlanks;
return %subst(blanks : 1 : startBlanks)
+ text
+ %subst(blanks : 1 : endBlanks);
/end-free
P center e
D proc pi a len(16773100) varying
D rtnparm opdesc
D p1 10a
D p2 10a options(*varsize)
D p3 10a options(*omit : *nopass)
D num_parms s 10i 0
D parm_len s 10i 0
D desc_type s 10i 0
D data_type s 10i 0
D desc_info1 s 10i 0
D desc_info2 s 10i 0
D CEEDOD pr
D parm_num 10i 0 const
D desc_type 10i 0
D data_type 10i 0
D desc_info1 10i 0
D desc_info2 10i 0
D parm_len 10i 0
D feedback 12a options(*omit)
/free
// Get information about parameter p2
callp CEEDOD(%parmnum(p2) : desc_type : data_type
: desc_info1 : desc_info2
: parm_len : *omit);
if parm_len < 10;
// The parameter passed for p2 is shorter than 10
endif;
// Find out the number of parameters passed
num_parms = %parms();
// If all three parameters were passed, num_parms = 4
// test if p3 was passed
if num_parms >= %parmnum(p3);
// Parameter p3 was passed
if %addr(p3) <> *null;
// Parameter p3 was not omitted
endif;
endif;
1. The RPG prototype
D myproc pr 200a rtnparm
D name 10a const
2. A CL module calling this RPG procedure
dcl &retval type(*char) len(200)
callprc myproc parm(&retval 'Jack Smith')
1. CL procedure GETLIBTEXT
PGM PARM(&retText &lib)
DCL &retText type(*char) len(50)
DCL &lib type(*char) len(10)
/* Set &retText to the library text */
rtvobjd obj(&lib) objtype(*lib) text(&retText)
return
2. RPG procedure calling this CL procedure using the RTNPARM keyword
D getLibText pr 50a rtnparm
D name 10a const
/free
if getLibText('MYLIB') = *blanks;
...