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.
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.
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.
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 2: Index 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.
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 2: Index 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.