Guru: With Procedure Driven RPG, Be Precise With Options(*Exact)
June 3, 2024 Gregory Simmons
Introduced to the RPG language in V7R2 TR1 and V7R3 TR7, the Options(*Exact) enables RPG programmers to adopt a more defensive coding style. Defensive coding is something all developers should be practicing.
DISCLAIMER: The edibility of the mushrooms listed in my test program are purely to give the program a little context and make it interesting. Their edible status is from the publication by the Missouri Department of Conservation called A Guide to Missouri’s Edible and Poisonous Mushrooms. Before foraging for and/or consuming any wild mushroom, do your research and be safe.
**Free Ctl-Opt Main(Test_Exact_Options); Ctl-Opt Debug Option(*SrcStmt:*NoDebugIO); Ctl-Opt ActGrp(*Caller); Dcl-Proc Test_Exact_Options; Dcl-s answer Char(1) Inz(''); Dcl-s fry_it_up Ind; Dcl-s mushroom_name Char(30) Inz('Chicken of the Woods False'); fry_it_up = is_edible_mushroom(mushroom_name); If fry_it_up; Dsply 'Fry it up!' '' answer; Else; Dsply 'Don''t fry it up!' '' answer; Endif; On-Exit; End-Proc Test_Exact_Options;
In the above example, I’ve written a simple linear-main RPG program to call a procedure and report whether the mushroom species is edible or not. Note that in this iteration, the variable mushroom_name is 30 long and initialized to ‘Chicken of the Woods False’.
The is_edible_mushroom procedure looks like this:
Dcl-Pi is_edible_mushroom Ind; p_mushroom_name Char(20); End-Pi; Dcl-s abnormal_End Ind Inz(*Off); If p_mushroom_name in %List('Chanterelle':'Chicken of the Woods': 'Hen of the Woods':'Morel'); Return *On; Else; Return *Off; Endif; On-Exit; End-Proc is_edible_mushroom;
Okay, so this is a simple procedure. If my %List BIF contains the passed value, then return true, meaning it’s edible; otherwise, return false – it’s not. Notice that ‘Chicken of the Woods False’ was passed in, but the procedure interface declared that the p_mushroom_name parameter was only 20 long. Thus, when calling this program, the received value was ‘Chicken of the Woods’ and the word ‘False’ got cut off. So, this program incorrectly informs the user to ‘Fry it up!’.
Now, if I change the procedure interface of the is_edible_mushroom to include the Options(*Exact) like this:
Dcl-Proc is_edible_mushroom; Dcl-Pi is_edible_mushroom Ind; p_mushroom_name Char(20) Options(*Exact); End-Pi; Dcl-s abnormal_End Ind Inz(*Off); If p_mushroom_name in %List('Chanterelle':'Chicken of the Woods': 'Hen of the Woods':'Morel'); Return *On; Else; Return *Off; Endif; On-Exit; End-Proc is_edible_mushroom;
When I recompile the program, the compiler will throw an RNF3249 error “The type or attributes of the parameter 1 do not meet the OPTIONS(*EXACT) requirements. Reason: LEN. (30)”. By including the Options(*Exact) on the parameter, I have written this procedure in a more defensive coding style. Which is good! In this instance, I prevented potentially telling a user to fry up a poisonous mushroom. I’m confident you can see how this can avert a potential crisis in your business.
Now, the above example is where my parameter being passed was longer than the procedure interface dictates. Let’s cover a couple scenarios where the parameter being passed in is shorter than the procedure interface specifies.
If I only change the definition and initialization of the mushroom_name variable as such:
Dcl-s mushroom_name Char(19) Inz('Chicken of the Wood');
The result is a bit unexpected. The compiler, instead of returning the RNF3249 error from before, now returns an RNF7535 error “The type and attributes of parameter 1 do not match those of the prototype. (30)”. I would have expected the RNF3249, but alas, the desired result was still the same; the compile failed.
Now, if I had the keyword Const on the parameter in the procedure interface like this:
Dcl-s mushroom_name Char(19) Inz('Chicken of the Wood'); Dcl-Pi is_edible_mushroom Ind; p_mushroom_name Char(20) Const; End-Pi;
This would be bad, because the compile would succeed.
And now, let’s keep the passing parameter the same and change the procedure interface to include both the Const and Options(*Exact) keywords:
Dcl-s mushroom_name Char(19) Inz('Chicken of the Wood'); Dcl-Pi is_edible_mushroom Ind; p_mushroom_name Char(20) Const Options(*Exact); End-Pi;
After recompiling, we will see that the compile is still successful. Wait, what?! But I have the Options(*Exact) specified. Doesn’t the parameter have to then be defined exactly like the procedure interface dictates? The conclusion is that the Const and Options(*Exact) keywords don’t work together like one would think. Apparently, when using both of these keywords together, *Exact is only going cause the compile to fail if the variable being passed into the procedure is longer than expected.
In summary, I feel that making use of Options(*Exact) is useful in helping us all adopt a more defensive coding style. Just be careful when combining the two keywords.
Until next time, happy coding.
Gregory Simmons is a software engineer with P.C. Richard & Son. He started on the IBM i platform in 1994, graduated with a degree in Computer Information Systems in 1997 and has been working on the OS/400 and IBM i platform ever since. He has been a registered instructor with the IBM Academic Initiative since 2007, and holds a COMMON Application Developer certification. When he’s not trying to figure out how to speed up legacy programs, he enjoys speaking at technical conferences, running, backpacking, hunting, and fishing.
RELATED STORIES
Testing URLs With HTTP_GET_VERBOSE
Guru: Fooling Around With SQL And RPG
Guru: Procedure Driven RPG And Adopting The Pillars Of Object-Oriented Programming
Guru: Getting Started With The Code 4 i Extension Within VS Code
Guru: Procedure Driven RPG Means Keeping Your Variables Local
Guru: Procedure Driven RPG With Linear-Main Programs
Guru: Speeding Up RPG By Reducing I/O Operations, Part 2
Guru: Speeding Up RPG By Reducing I/O Operations, Part 1
Guru: Watch Out For This Pitfall When Working With Integer Columns