Most RPG programmers today are familiar with specifying the initialize (INZ) keyword on a D-spec to provide an initial value for a variable. Did you realize, though, that there are special values that you can specify inside the INZ keyword? In this article, I explain these special values and demonstrate how to use them.
Here's a list of the special values that you can use in the INZ keyword:
| Keyword | Applies to | Release | Description |
| *SYS | Date fields | V3R7 | Initialize with the current date from the system clock |
| *JOB | Date fields | V3R7 | Initialize with the job date |
| *USER | Alphanumeric | V4R4 | Initialize with the current user profile name |
| *EXTDFT | External DS | V4R4 | Initialize with the default values from the DDS/DDL |
| *LIKEDS | Derived DS | V5R1 | Copy initial values of the original data structure |
| *NULL | Java Object | V5R1 | Set object reference to point to nothing |
Historically, to set the value of a date, we moved the UDATE or *DATE field into another variable. This action would set the variable to the job date. Or, if we needed the system date, we used the TIME opcode to get the date and time, which was a little more work.
One thing that I dislike about those "good ol' days" is that far too many folks inappropriately used the job date (either *DATE or UDATE). Why? Because moving *DATE was a lot easier than invoking the TIME opcode.
Fortunately, today, getting the current time from the system clock is easy. Simply define a date field and initialize it to *SYS:
D MyDate s D inz(*sys)
/free
dsply ('Current date is ' + %char(MyDate));
return;
/end-free
Of course, you do have to remember that the date is set to the system date only when the variable is initialized. For global variables, that means the first time the module is invoked. For variables local to a subprocedure, the date is reinitialized each time the procedure is run, unless the variables are declared as static.
If your program runs in a loop that might need to cross over into the next day, then you might want to update the date from the system clock in the middle of your loop. When you call the %date() BIF with no parameters, the current system date is retrieved.
For example, the following never-ending loop displays the current date from the system clock. Because it calls %date() in the loop, the system date is re-retrieved each time through, so if the program is left running past midnight, the date changes.
D MyDate s D
/free
dow 1 = 1;
MyDate = %date();
dsply ('Current date is ' + %char(MyDate));
enddo;
return;
/end-free
Most of the time, I think the system date is the right choice when you want to use the current date in an RPG program. Unless someone has changed it with the CHGJOB command (or a similar tool) the job date is the date that your job started. If the job stays active past midnight, the job date will be wrong. Unfortunately, far too many programs contain this mistake!
However, if you do prefer to use the job date, it's not any harder to use than the system date. Just specify *JOB instead of *SYS:
D MyDate s D inz(*JOB)
The *USER keyword retrieves the current user profile name and stores it in the variable. For example:
D MyUserId s 10a inz(*USER)
Check the value of MyUserId, and you see that it's set to the user profile running your job. Using this feature is much easier than coding a program status data structure (PSDS) or, even worse, calling a CL program just to retrieve the current user profile name.
If you're running a job in which the user profile changes, such as when you do profile swapping or run your program from a network server, *USER is initialized with whomever the current user is at the time that the INZ keyword is executed.
RPG has always been able to declare a data structure as being "like" a record from a file. Did you know that you can also use this feature to set the default values of the fields in the data structure? For example, considering the following physical file:
A R EXTDFTF
A FIELD1 10A DFT('SCOTT')
A FIELD2 10A DFT('KLEMENT')
A FIELD3 5P 0 DFT(1)
If you want to create a data structure that has the same field names (as above) and starts with whatever values you specify for DFT, you could use code like this:
D MyDs e ds extname(EXTDFT)
D inz(*extdft)
Because of the way I've coded that, the MyDS field automatically includes the FIELD1, FIELD2, and FIELD3 values from the DDS. Because I specified the INZ keyword with *EXTDFT, the fields start with "Scott", "Klement", and 1, respectively.
See how easy that was?
The *LIKEDS keyword is very similar to the *EXTDFT one that I just demonstrated, except that it operates on another data structure in the same program instead of operating on an externally defined data structure. For example:
D DsOne ds qualified
D First 10a inz('Scott')
D Last 10a inz('Klement')
D Age 3p 0 inz(102)
D DsTwo ds likeds(DsOne)
D inz(*likeds)
/free
dsply DsTwo.First;
dsply DsTwo.Last;
dsply DsTwo.Age;
*inlr = *on;
/end-free
DsOne has subfields that were initialized when the program started up. DsTwo is defined with LIKEDS, and that means that DsTwo has the same subfields as DsOne had. The INZ(*LIKEDS) tells the system to initialize DsTwo to the same initial values that DsOne had.
In V5R1, RPG gained the ability to call methods in Java objects. As part of that support, IBM added an O data type that refers to a Java object. You can use the *NULL special value to initialize the O data type as follows:
D MyObject s O Class(*java:'java.lang.String')
D inz(*null)
The inz(*null) means that this object reference field has not yet been associated with an actual Java object in the Java Virtual Machine (JVM).
However, I find INZ(*NULL) useless for the following reasons:
Given those points, there's little reason to explicitly code INZ(*NULL). Just code the object reference without the INZ keyword, and you'll be all set.
Good luck, and happy initializing!