Dynamic Arrays

Dynamic arrays or Varying dimension arrays were introduced to IBM i in V7R4 and this is the minimum version and release in which they can be used.

When you define a varying dimension array you are defining the maximum length you want the array to be not the actual size of the array. You can do this in two ways but always using the built-in function %ELEM.

One more thing to consider when talking about the array size is the maximum size. The maximum size of the array has not changed and it is cannot be greater than 16733104 bytes so the combination of number of elements and size of each element cannot be greater than 16733104 bytes.

%ELEM

Before going with the definition of varying dimension arrays let’s take a look at the built-in function that will be used to establish the size of the array and the options available.

Maybe you know %ELEM as the built-in function that returns the number of elements of an array, table or array data structures as an unsigned integer.

				
					dcl-s array1 char(5) dim(100);
dcl-s array2 like(array1) dim(%elem(array1)); //Same number of elements as array1
dcl-ds ds1 dim(10);
    fld1 char(10);
    fld2 packed(5);
end-ds;

dcl-s numElem packedÇ(3);

numElem = %elem(array1);  // numElem = 100
numElem = %elem(array2);  // numElem = 100 
numElem = %elem(ds1);     // numElem = 10 
				
			

When %ELEM is used with varying dimension arrays it can be used with a second parameter to increase or decrease the number of elements of the array or to get the actual or maximum number of elements.

  • %ELEM(array:*KEEP) allows you to increment or decrement the array without initializing/resetting its elements.
  • %ELEM(array:*ALLOC) allows you to get or set the size of the array.
  • %ELEM(array:*MAX) returns the maximum number of elements the array can have.

Varying  Dimension Arrays – Definition

Varying dimension arrays can be defined in two ways, using *VAR or using *AUTO. In both cases it is indicating that the number of elements in the array will not always be the maximum. Also, the array will work in different ways if you use *VAR or *AUTO.

*VAR

With *VAR the size of the array does not grow automatically, so it must be set with the %ELEM function. Initially RPG declares the array with the smallest possible size (0 bytes). As soon as its size is set via %ELEM, RPG will increase the amount of memory used according to the size and length of the elements. If you want to keep old values of the new positions you can use *KEEP and they won’t be initialized. The normal behavior if you don’t use *KEEP is to initialize the values to the value specified in INZ keyword or the default value for the data type. 
 
One more thing to consider is that the debugger doesn’t know that the dimension of the array is variable, so it’s possible that if you’re debugging you’ll see old values in positions that aren’t available right now. While debugging you can evaluate _QRNU_VARDIM_ELEMS_arrayname to get the current number of elements the array has.

Example 1:

				
					dcl-s array1 char(10) dim(*var:1000) inz('*');
dcl-s i      packed(4);

%elem(array1) = 10;

for i = 1 to %elem(array1);
  array1(i) = %char(i);
endfor;     

array1(11) = '11';

%elem(array1) = 20;
array1(11) = '11';

%elem(array1) = 5;

%elem(array1:*keep) = 8;

%elem(array1) = 20;
				
			

Explanation:

Line 1: A varying length array is declared whose elements are going to be character strings of  length 10. The variable part of the array is set to a maximum of 1000 elements. At this point, since %elem has not been used yet, the array has 0 elements and occupies 0 bytes in memory.

Line 2Index variable used in for loop. 

Line 4: %elem is used to set the number of elements in the array to 10. Thereafter the  array occupies 100 bytes in memory (10 elements of 10 bytes each) and positions from 1 to 10 have the value ‘*’.

Line 6: The array can be used in the usual way for example to store the representation of the first 10 numbers.

Line 10: At this point of the code you will receive the inquiry message RNQ0121 “An array index is out of range (C G D F)  because you are trying to write at position 11 and the maximum size of the array at this moment is 10. If you want to test the rest of the program you must comment this line and compile again.

Line 12: The maximum length of the array is set to 20 elements. Elements 11 through 20 are initialized to ‘*’.

Line 13: This time the assignment works well because there is enough room in the array to hold the value.

Line 15: Now the array is decreased to 5 elements. Elements 6 to 11 still have their values ‘6’, ‘7’, ‘8’, ‘9’, ’10’ and ’11’ due to previous assignment.

Line 17: The array is extended to 8 elements and as *KEEP is used values for positions 6, 7 and 8 remain the same.

Line 19: This time *KEEP is not used so elements 9 through 20 are initialized with the value of INZ keyword.

*AUTO

With *AUTO the number of array elements automatically grows if a position is accessed after the last array element. It only grows, not decreases if a position smaller than the current number of elements is accessed.

To reduce the number of elements of the array you can use %ELEM assigning a number smaller than the current number of elements.

One more thing to consider is the use of *NEXT as index for the array. If used to assign a value to the array it will extend the array in one position and then assign the value to this new position.

Example 2:

				
					dcl-s array1   char(10) dim(*auto:1000) inz('*');
dcl-s i        packed(4);

array1(10) = '10';

for i = 1 to 10;
  array1(*next) = %char(i + 10);
endfor;

array1(30) = '30';

%elem(array1) = 10;

//array1(1001) = '1001';
				
			

Explanation:

Line 1: A varying length array is declared whose elements are going to be character strings of  length 10. The variable part of the array is set to a maximum of 1000 elements. At this point, since %elem has not been used yet and no value is assigned to any array position , the array has 0 elements and occupies 0 bytes in memory.

Line 2Index variable used in for loop. 

Line 4: String ’10’ is assigned to position 10 of the array. Now array1 has 10 elements, the first 9 initialized to ‘*’ and position ten has the value assigned.

Line 6: Now *NEXT is used as index of the array so values will be assigned in the next free position of the array and the array will increase the number of elements accordingly. When this line of code is executed positions 11 to 20 will have the same number in string format.

Line 10: Now the string ’30’ is assigned to position 30. The array will grow until this position and positions 20 to 29 will have the initial value of ‘*’.

Line 12: The maximum length of the array is set to 10 elements. When %elem is used with a value less than the maximum number of the array at this moment, the array size will be decreased.

Line 14: This line is commented because the index is greater than the maximum number declared so it will raise a compiler error RNF0530: Array index is not valid.

I hope you have a clearer idea about dynamic arrays or at least clarified how they work.

Personally I prefer to declare them with *AUTO and use *NEXT to add elements but both options are very good.

Thanks and stay tuned for the next post.

Leave a Reply

Your email address will not be published. Required fields are marked *