What is an RPG Procedure anyway?

IBM i

Jan 08

another snippet from an old document I found in a dim dark and hazy corner of an even older HDD… rather than let it disintegrate, here it is migrating to the web just in the (extreme) off chance that it may be useful to someone out there. Hey.. if YOU are reading this then its dont its job 😉

Procedure Basics

A very typical place to start with new procedures is to prototype a system API, like the translate API. Original inline code looked like this:

C PARM FLDLEN
C PARM TEXT
C PARM TBLNAM
C PARM LIBNAM

This code frag was in 3 places in the program: a perfect candidate for a subroutine. There were 3 different fields being translated to upper case: TEXT, DESC and TITLE. This meant inline code that looked like this:

C MOVELTEXT XFIELD
C EXSR UCASE

C MOVELDESC XFIELD
0C EXSR UCASE

C MOVELTITLE XFIELD
C EXSR UCASE

with a subr like:

C UCASE BEGSR
C CALL 'QDCXLATE'
C PARM FLDLEN
C PARM XFIELD
C PARM TBLNAM
C PARM LIBNAM
C ENDSR

This subr can easily be turned into a procedure:

C CallP UCASE(Text)

* Translate lower to upper case
P UCASE B
D UCASE PI
D WorkString 50

C CALL 'QDCXLATE'
C PARM FLDLEN
C PARM WorkString
C PARM TBLNAM
C PARM LIBNAM
C Return
P UCASE E

This procedure has a problem: it isn’t stand-alone because of the three
global variables FLDLEN, TBLNAM and LIBNAM. In order to use this procedure in another program, I’d need to define and populate these exact field names in the new program. Sounds like a perfect use for some more parameters:

C CallP UCASE(Text:'QSYSTRNTBL':'QSYS')

* Translate lower to upper case
P UCASE B
D UCASE PI
D WorkString 50
D XlateTableNam 10 Value
D XlateTableLib 10 Value

D WorkStringLen S 5p 0

C Eval WorkStringLen = %len(WorkString)

C CALL 'QDCXLATE'
C PARM WorkStringLen
C PARM WorkString
C PARM XlateTableNam
C PARM XlateTableLib
C Return
P UCASE E

This is a bit better because if I decide to change the length of the input string, I don’t need to change the guts of the code – it determines the length using the %len BIF. But still, it seems kind of goofy to specify the translate table name for every CALLP to a procedure named UCASE. This procedure really does the function TRANSLATE. If I rename this one TRANSLATE, I could make a new procedure called UCASE that will only perform the uppercase function:

C CallP UCASE(Text)

* Translate lower to upper case
P UCASE B
D UCASE PI
D WorkString 50

C CallP Translate(WorkString:'QSYSTRNTBL':'QSYS')
C Return

P UCASE E

* Translate string according to supplied table
P Translate B
D Translate PI
D WorkString 50
D XlateTableNam 10 Value
D XlateTableLib 10 Value

D WorkStringLen S 5p 0

C Eval WorkStringLen = %len(WorkString)

C CALL 'QDCXLATE'
C PARM WorkStringLen
C PARM WorkString
C PARM XlateTableNam
C PARM XlateTableLib
C Return
P Translate E

Difference between Procedure and Subroutine.

A procedure is encapsulated, where a subroutine is not.

That is, a procedure can see variables that it defines, but not variables that the main program defines. This makes it a lot easier to
determine what a procedure is actually doing and where it’s getting it’s return value(s).

This makes a procedure “stand alone”, and can be used in other programs with little modification (modification required for any File I/O
may be required)

It can be extremely difficult to copy a subroutine to another program, as you have to determine all the variables the subroutine uses, and what these are supposed to be set for, etc…

Follow

About the Author

IBM i Software Developer, Digital Dad, AS400 Anarchist, RPG Modernizer, Alpha Nerd 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 in the words of the most interesting man in the world: Stay thirsty my friend.