Give Me Fewer (Not More!) Parameters, Please!
August 2, 2016 Ted Holt
Today’s musings fall into the “why would anybody want to do that?” category. “Why would anybody want to be president?” asks Barack Obama. “Why would anybody steal a groundhog?” asks Rita in Groundhog Day. My question is, “Why would anybody pass 16,382 parameters to a subprocedure?” There is a better way. I stand second to none in my admiration for parameters. The first system I learned to program, the IBM System/3 Model 12, allowed no parameter passing to RPG programs or OCL procedures. Cloning diminished–and life improved–when I started working on a S/34, which allowed OCL procedures to receive positional parameters. Fast forward to 2016, when IBM increased the number of parameters that may be passed to an RPG subprocedure from 399 (which was already infinity to my little mind) to 16,382. And so I ask, “Why would anybody pass 16,382 parameters to a subprocedure?” To my way of thinking, the fewer the parameters, the better. The Basic Technique The better way to which I alluded is to combine related parameters into data structures. Here’s a small example. It uses programs, not subprocedures, but the idea is the same. Let’s say an RPG program needs to pass spooled file identification to CL program MAILMYSPLF, which will email the spooled file using third-party software. To uniquely identify a spooled file requires:
(It seems to me that the name of the spooled file should be optional, but I don’t make the rules.) We could pass these data as five parameters, of course, but since they are related, why not use a data structure? Here’s a copybook. // Definitions for parameter structures D JobID_t ds qualified template D Name 10a D User 10a D Number 6a D SplfData_t ds qualified template D Name 10a D Job likeds(JobID_t) D Number 10i 0 Here’s a copybook for the prototype of the CL program. D MailMySplf pr extpgm('MAILMYSPLF') D SplfData likeds(SplfData_t) Here are the relevant pieces of the RPG program. /include copybooks,ParmPgmCpy /include prototypes,MailMySplf D Splf ds likeds(SplfData_t) /free Splf . Name = 'WHATEVER'; Splf . Job . Name = 'WHATEVER'; Splf . Job . User = 'WHATEVER'; Splf . Job . Number = 'WHATEVER'; Splf . Number = whatever; MailMySplf (Splf); CL programs don’t have data structures, but they have something just as good. pgm parm(&inSplfID) dcl &inSplfID *char 40 dcl &SplfName *char 10 stg(*defined) defvar(&inSplfID 1) dcl &JobID *char 26 stg(*defined) defvar(&inSplfID 11) dcl &JobName *char 10 stg(*defined) defvar(&JobID 1) dcl &JobUser *char 10 stg(*defined) defvar(&JobID 11) dcl &JobNbr *char 6 stg(*defined) defvar(&JobID 21) dcl &SplfNbr *int 4 stg(*defined) defvar(&inSplfID 37) The term STG(*DEFINED) means that this variable is another name for part of another variable. The DEFVAR parameter tells which variable this one is based on and the position at which this variable overlays the other. The area of memory that was defined as a data structure in the RPG program is a 40-byte variable called &inSplfID in the CL program. The other variables are alternate names for pieces of &inSplfID. Three of the variables–&SplfName, &JobID, and &SplfNbr–redefine the spooled file name, job identification, and spooled file number. The &JobID is further redefined as job name, user profile, and number. The CL program refers to these redefinitions as if they were subfields of a data structure. Here’s the command to email the spooled file. mailthis file(&SplfName) + job(&JobNbr/&JobUser/&JobName) + splnbr(&SplfNbr) + to('president@whitehouse.gov ') A Step Further These programs work well, but you astutely realize that job information is not necessary when the spooled file is created in the same job that sends the email. You reason correctly that it would be nice to have a second interface that doesn’t require job information. A very common practice is to clone the programs, remove the job information from the data structure, and make the CL program clone retrieve the job information. I like to clone programs as much as I like to spend money on dentists. Instead, I prefer to add flexibility to programs when it makes sense to do so. Let’s define two data structures to hold spooled file identification. One of them–let’s call it format A–is like the one given above. The other, which we’ll call format B, doesn’t include the job information. When you call the CL program, you must tell it which of the formats the data structure uses. You can pass the format ID in a separate parameter or you can include the format as the first field of the data structure. For an existing application, it usually makes more sense to use a separate parameter, which defaults to the existing format. I use the other approach in my example. First, the copybook with the data structure definitions. // Definitions for parameter structures D JobID_t ds qualified template D Name 10a D User 10a D Number 6a D SplfData_A_t ds qualified template D FormatID 1a D Name 10a D Job likeds(JobID_t) D Number 10i 0 D SplfData_B_t ds qualified template D FormatID 1a D Name 10a D Number 10i 0 The procedure prototype for the CL program has changed a bit. D MailMySplf pr extpgm('MAILMYSPLF') D SplfData 41a const Here’s an RPG caller that must pass job information as part of the data structure. /include copybooks,ParmPgmCpy /include prototypes,MailMySplf D Splf ds likeds(SplfData_A_t) /free Splf . FormatID = 'A'; Splf . Name = 'WHATEVER'; Splf . Job . Name = 'WHATEVER'; Splf . Job . User = 'WHATEVER'; Splf . Job . Number = 'WHATEVER'; Splf . Number = whatever; MAILMYSPLF (Splf); Here’s an RPG caller that does not need to pass job identification. /include copybooks,ParmPgmCpa /include prototypes,MailMySplf D Splf ds likeds(SplfData_B_t) /free Splf . FormatID = 'B'; Splf . Name = 'WHATEVER'; Splf . Number = whatever; MailMySplf (Splf); Finally, program MailMySplf: pgm parm(&inSplfID) dcl &inSplfID *char 41 dcl &FormatID *char 1 stg(*defined) defvar(&inSplfID 1) dcl &FormatA *char 40 stg(*defined) defvar(&inSplfID 2) dcl &FormatB *char 14 stg(*defined) defvar(&inSplfID 2) dcl &A_SplfName *char 10 stg(*defined) defvar(&FormatA 1) dcl &A_JobID *char 26 stg(*defined) defvar(&FormatA 11) dcl &A_JobName *char 10 stg(*defined) defvar(&A_JobID 1) dcl &A_JobUser *char 10 stg(*defined) defvar(&A_JobID 11) dcl &A_JobNbr *char 6 stg(*defined) defvar(&A_JobID 21) dcl &A_SplfNbr *int 4 stg(*defined) defvar(&FormatA 37) dcl &B_SplfName *char 10 stg(*defined) defvar(&FormatB 1) dcl &B_SplfNbr *int 4 stg(*defined) defvar(&FormatB 11) dcl &SplfName *char 10 dcl &JobName *char 10 dcl &JobUser *char 10 dcl &JobNbr *char 6 dcl &SplfNbr *int 4 select when (&FormatID *eq 'A') do chgvar &SplfName &A_SplfName chgvar &JobName &A_JobName chgvar &JobUser &A_JobUser chgvar &JobNbr &A_JobNbr chgvar &SplfNbr &A_SplfNbr enddo when (&FormatID *eq 'B') do chgvar &SplfName &B_SplfName chgvar &SplfNbr &B_SplfNbr rtvjoba job(&JobName) user(&JobUser) nbr(&JobNbr) enddo otherwise do sndpgmmsg msgid(cpf9898) msgf(qcpfmsg) + msgdta('Invalid format "' *cat &FormatID *cat '"') + msgtype(*escape) enddo mailthis file(&SplfName) + job(&JobNbr/&JobUser/&JobName) + splnbr(&SplfNbr) This program accepts spooled file identification in either format. The program tests &FormatID, which is the first byte of &inSplfID, to determine how the data is structured. Variables &FormatA and &FormatB overlay the remainder of the input parameter. Variables that begin with &A_ redefine the format A data, and variables that begin with &B_ redefine format B data. This concept is behind many of the IBM API’s. For example, the List Spooled Files (QUSLSPL) API allows four data structure formats. Someday, When Humans Are Superfluous. . . Pundits say that truck drivers will soon be out of work. Computers will drive trucks, and shortly thereafter, passenger cars. Maybe it’s only a matter of time until computers program computers. If so, they won’t have any trouble passing thousands of parameters from one procedure to another. Until then, we humans will have to manage, and passing data structures can help us do so. Why would anybody want to play the oboe? Ted Holt welcomes your comments and questions. Email him through the IT Jungle Contacts page.
|
Ted,
Found this article while trying to figure out what I was doing wrong with passing a data structure as a parameter.
The oboe video made me very glad I’m a flute player and don’t have to deal with making finicky reeds. Much respect to oboists.