Wednesday, July 20, 2016

The versatile Clear operation code

use the clear operation code to initialize field, variable, record format. no more z-add

When I wrote about using DEFAULT in SQL statements it made me think if there is an equivalent in RPG. The Clear operation code sprung to mind. CLEAR has been around for many releases, including in RPGIII. It initializes the value of a variable, field, data structure, array, record format, etc. to the data type's default value.

I use CLEAR extensively because…

 

Initializing variables

In the very simple example, below, I came up with the most commonly used data types I use. I did not bother to include signed, integer, and unsigned integer variables as they all act the same as the packed variable.

01  dcl-s xChar char(10) inz('Test') ;
02  dcl-s xPacked packed(3) inz(123) ;
03  dcl-s xDate date inz(*sys) ;
04  dcl-s xTime time inz(*sys) ;
05  dcl-s xTimestamp timestamp inz(*sys) ;
06  dcl-s xInd ind inz('1') ;

07  clear xChar ;
08  clear xPacked ;
09  clear xDate ;
10  clear xTime ;
11  clear xTimestamp ;
12  clear xInd ;

For those of you unfamiliar with the INZ(*SYS), used on lines 3 – 5, you can learn about it in the post Initializing variables with special values.

The Clear operation initializes the variables to be:

Data type Value after Clear
Alphanumeric Blank
Numeric (packed, signed, integer, unsigned integer) Zero
Date d'0001-01-01'
Time t'00.00.00'
Timestamp z'0001-01-01-00.00.00.000000'
Indicator Off

The handling of the date, time, and timestamp variables is different when I use the CLEAR when compared to using DEFAULT in a SQL statement. SQL's DEFAULT would have initialized those variables to the current date, time, and timestamp.

 

Initializing data structures

Initializing a data structure is one of the reasons I love the CLEAR.

01  dcl-ds xDs qualified ;
02    Char char(10) inz('ds test') ;
03    Packed packed(3) inz(987) ;
04    Date date inz(d'2016-12-25') ;
05    Time time inz(t'13.20.00') ;
06    Timestamp timestamp inz(*sys) ;
07    Ind ind inz('1') ;
08  end-ds ;

09  clear xDs ;
10  reset xDs ;

Lines 1 - 8: I am initializing the sub-fields of my data structure with values at program initialization.

Line 9: With this one statement all of the sub-fields are initialized with their data type's default values:

> EVAL xds
  XDS.CHAR = '          '
  XDS.PACKED = 000.
  XDS.DATE = '0001-01-01'
  XDS.TIME = '00.00.00'
  XDS.TIMESTAMP = '0001-01-01-00.00.00.000000'
  XDS.IND = '0'

Line 10: I find that not many programmers are aware of the Reset operation code, RESET. This operation code will reset the values of a field or data structure to its value at program initialize. So after line 10 is executed the data structure now contains:

> EVAL xds
  XDS.CHAR = 'ds test   '
  XDS.PACKED = 987.
  XDS.DATE = '2016-12-25'
  XDS.TIME = '13.20.00'
  XDS.TIMESTAMP = '2016-06-23-12.46.29.092000'
  XDS.IND = '1'

I am sure you all agree that is pretty cool, and useful, which is why I felt I had to mention the RESET.

What about other types of Data Structures:

  • Data Structures arrays – I will cover them in the section about arrays below
  • Multiple occurrence Data Structures

I have not used multiple occurrence Data Structures since I discovered Data Structure arrays, but there are many programs and programmers who still use them.

01  dcl-ds xMultiDs qualified occurs(2) ;
02    First char(1) ;
03    Second char(1) ;
04  end-ds ;

05  exsr LoadMultiDs ;
06  %occur(xMultiDs) = 1 ;
07  clear xMultiDs ;
08  %occur(xMultiDs) = 2 ;

09  exsr LoadMultiDs ;
10  %occur(xMultiDs) = 1 ;
11  clear *all xMultiDs ;
12  %occur(xMultiDs) = 2 ;
    //=======================
13  begsr LoadMultiDs ;
14    %occur(xMultiDs) = 1 ;
15    xMultiDs.First = '1' ;
16    xMultiDs.Second = '1' ;

17    %occur(xMultiDs) = 2 ;
18    xMultiDs.First = '2' ;
19  endsr ;

Lines 1 – 4: This is my definition of my multiple occurrence Data Structure.

Line 5: Rather than repeat the code to load occurrences of the Data Structure I have placed the logic in a subroutine, lines 13 – 19.

Line 6: Get the first occurrence of the Data Structure.

Line 7: Perform the clear.

Line 8: Get the second occurrence. If I use debug I will see that the second occurrence still contains the data I loaded into it.

Lines 9 – 12: Are basically the same except…

Line 11: This time the clear has the *ALL keyword. This means that all occurrences are cleared, not just the current one.

 

Initializing arrays

Using CLEAR I can clear an entire array in one statement.

01  dcl-s xArray char(1) dim(5) ;

02  xArray(1) = '1' ;
03  xArray(2) = '2' ;
04  xArray(3) = '3' ;
05  xArray(4) = '4' ;
06  xArray(5) = '5' ;

07  clear xArray ;

Even if the array is a Data Structure array.

01  dcl-ds xArrayDs qualified dim(2) ;
02    First char(1) ;
03    Second char(1) ;
04  end-ds ;

05  xArrayDs(1).First = '1' ;
06  xArrayDs(1).Second = '1' ;
07  xArrayDs(2).First = '2' ;

08  clear xArrayDs ;

 

Initializing record format

I can use the clear to initialize an entire record format from a file, no matter if it is a physical, logical, display, or printer file. Below is a simple physical file I will be using in these examples. Notice how the field FDFT has a default value, and FNULL allows null and its default is also null.

A          R TESTFILER
A            FCHAR          3A
A            FPACKED        3P 0
A            FDATE           L
A            FTIME           T
A            FTINESTAMP      Z
A            FDFT           1A         DFT('A')
A            FNULL          1A         ALWNULL
A                                      DFT(*NULL)
A          K FCHAR

I have added a record to the file, the dash indicates that the field is null.

FCHAR  FPACKED  FDATE       FTIME     FTINESTAMP                  FDFT  FNULL
 AAA     111    1995-02-21  05.21.13  1962-01-31-14.08.33.000000   A      -

In my first example I am going to read the file, clear the record format, and write the record to the file.

01  dcl-f TESTFILE usage(*input:*output)
                  keyed ;

02  read TESTFILER ;
03  clear TESTFILER ;
04  write TESTFILER ;

The file now has two records. As the second record was cleared it contains the data types's defaults, not the field defaults. Which is why the field FSDFT now contains a blank. FNULL remains unchanged as you cannot clear a null value.

FCHAR  FPACKED  FDATE       FTIME     FTINESTAMP                  FDFT  FNULL
 AAA     111    1995-02-21  05.21.13  1962-01-31-14.08.33.000000   A      -
           0    0001-01-01  00.00.00  0001-01-01-00.00.00.000000          -

Before my next example I changed the value of FNULL to set off the null indicator and to contain "N". If you are unfamiliar with null indicators in RPG you need to read Handling null in RPG.

In this example I read the file, I clear the record format and use the *NOKEY keyword, and then write the record back to the file.

02  read TESTFILER ;
03  clear *nokey TESTFILER ;
04  write TESTFILER ;

The *KEY keyword "protects" the key field from being cleared, therefore, the records in my file now look like.

FCHAR  FPACKED  FDATE       FTIME     FTINESTAMP                  FDFT  FNULL
 AAA     111    1995-02-21  05.21.13  1962-01-31-14.08.33.000000   A      N
 AAA       0    0001-01-01  00.00.00  0001-01-01-00.00.00.000000

 

As you can see the CLEAR is a really versatile operation code that deserves to be included in your programs. It will save you a lot of extra lines of code to achieve the same result, and make it easier for others to understand.

 

You can learn more about the CLEAR operation code from the IBM website here.

 

This article was written for IBM i 7.2, and should work for earlier releases too.

4 comments:

  1. You can override the default INZ value in the *INZSR so that when you RESET a variable it will actually go to the value after the *INZSR?

    ReplyDelete
    Replies
    1. You are correct. If I initialize a variable with a value in a DCL-S, then I change the value in the *INZSR, when I use the RESET operation the value it is changed to is the value I set it to in the *INZSR.

      Delete
    2. ... that's why it is important to understand the difference between CLEAR and RESET. In order of clean coding and readability, INZ values should always be set using the INZ keyword! It is a pain, IBM keeps supporting this stoneage stuff ...

      Delete

To prevent "comment spam" all comments are moderated.
Learn about this website's comments policy here.

Some people have reported that they cannot post a comment using certain computers and browsers. If this is you feel free to use the Contact Form to send me the comment and I will post it for you, please include the title of the post so I know which one to post the comment to.