Guru: The Case for Mixed-Case Procedure Names
July 14, 2020 Paul Tuohy
Using mixed case makes source code easier to read and easier to debug. I programmed in all upper case for many, many years, so I don’t recoil in horror when I see something in all uppercase. However, it’s a bit more difficult for developers who aren’t quite as long in the tooth as I am. To them, all uppercase is pretty abhorrent and bad (and I don’t mean bad as in good).
There is a potential case issue with subprocedure names: there are at least three places on the system where the system shows subprocedure names in uppercase, regardless of how they are coded. Luckily, this is something that is easily addressed, so with a thought to those who follow in your footsteps, you may want to consider standardizing on the use of extProc(*dclCase).
The conversion of subprocedure names to uppercase can be seen in the exports for a service program (DSPSRVPGM with DETAIL(*PROCEXP)).
So, if we look at the exports for a service program (DSPSRVPGM with DETAIL(*PROCEXP)):
Procedure Exports: Procedure Name ARGOPT CALCULATEDEDUCTIONS *NO CALCULATEPAY *NO CALCULATETAX *NO GETINCOME *NO
Or the call stack in a job (DSPJOB option 11):
PAYCALC1 TESTSTUFF _QRNP_PEP_PAYCALC1 PAYCALC1 TESTSTUFF 600 PAYCALC1 PAYCALC TESTSTUFF 800 CALCULATEPAY PAYCALC TESTSTUFF 1400 GETINCOME PAYCALC TESTSTUFF 2000 CALCULATETAX PAYCALC TESTSTUFF 2800 CALCULATEDEDUCTIONS
Or the details of an error message (F1 on a message in the job log then F9):
From program . . . . . . . . . : TRYCASE From library . . . . . . . . : TESTSTUFF From module . . . . . . . . : TRYCASE From procedure . . . . . . . : GETRESULTOFACOOLCALCULATION From statement . . . . . . . : 81 To program . . . . . . . . . . : TRYCASE To library . . . . . . . . . : TESTSTUFF To module . . . . . . . . . : TRYCASE To procedure . . . . . . . . : GETRESULTOFACOOLCALCULATION To statement . . . . . . . . : 81
We see that the subprocedure names are in uppercase.
Instead, we want to see this in the export list:
Procedure Exports: Procedure Name ARGOPT calculateDeductions *NO calculatePay *NO calculateTax *NO getIncome *NO
And this in the call stack:
PAYCALC1 TESTSTUFF _QRNP_PEP_PAYCALC1 PAYCALC1 TESTSTUFF 600 PAYCALC1 PAYCALC TESTSTUFF 800 calculatePay PAYCALC TESTSTUFF 1400 getIncome PAYCALC TESTSTUFF 2000 calculateTax PAYCALC TESTSTUFF 2800 calculateDeductions
And this in the message details:
From program . . . . . . . . . : TRYCASE From library . . . . . . . . : TESTSTUFF From module . . . . . . . . : TRYCASE From procedure . . . . . . . : getResultOfACoolCalculation From statement . . . . . . . : 81 To program . . . . . . . . . . : TRYCASE To library . . . . . . . . . : TESTSTUFF To module . . . . . . . . . : TRYCASE To procedure . . . . . . . . : getResultOfACoolCalculation To statement . . . . . . . . : 81
EXTPROC(*DCLCASE) to the rescue!
The EXTPROC keyword indicates the external name of a subprocedure. The EXTPROC keyword can be defined on a prototype (dcl-pr) or a procedure interface (dcl-p1) definition.
This prototype will result in an external name of get_otherStuff:
dcl-pr get_otherStuff end-pr;
Whereas this prototype will result in an external name of get_otherStuff:
dcl-pr get_otherStuff extProc('get_otherStuff') end-pr;
Repeating the subprocedure name can be tedious and open to typos, so better to make use of the special value of *DCLCASE, which means that the exact case of the subprocedure name will be used.
dcl-pr get_otherStuff extProc(*dclcase) end-pr;
This is all well and good for prototypes, but prototypes are not required for subprocedures that are not exported. In this case we specify the EXTPROC(*DCLCASE) on the procedure interface:
dcl-Proc calculateTax export; dcl-pi *n extProc(*dclCase) end-pr; end-Proc;
Using EXTPROC(*DCLCASE) means we now have easy-to-read subprocedure names in export lists, call stacks and message details.
RELATED STORIES
*DCLCASE with the EXTPROC keyword (IBM Knowledge Center)
The Geezer’s Guide To Free-Form RPG, Part 4: Prototypes and Procedure Interfaces
>>This prototype will result in an external name of >>get_otherStuff:
>>dcl-pr get_otherStuff end-pr;
Doesn’t this declaration yield an upper case external name?
I was thinking the same, I think it’s a typo. Also the last code example shouldn’t have the Export keyword as it is specifically referring to the example where a procedure is NOT exported.