When an ordinary array field is defined, you have to specify the index bounds exactly, hence the number of occurrences for each dimension. At runtime, the complete array field is existent by default; each of its defined occurrences can be accessed without performing additional allocation operations. The size layout cannot be changed anymore; you may neither add nor remove field occurrences.
However, if the number of occurrences needed is unknown at development time, but you want to flexibly increase or decrease the number of the array fields at runtime, you should use what is called an Xarray (eXtensible array).
An Xarray can be resized at runtime and can help you manage memory more efficiently. For example, you can use a large number of array occurrences for a short time and then reduce memory when the application is no longer using the array.
This document covers the following topics:
An Xarray is an array of which the number of occurrences is undefined
at compile time. It is defined in a DEFINE DATA
statement by
specifying an asterisk (*) for at least one index bound of at least one array
dimension. An asterisk (*) character in the index definition represents a
variable index bound which can be assigned to a definite value during program
execution. Only one bound  either upper or lower  may be defined as variable,
but not both.
An Xarray can be defined whenever a (fixed) array can be defined, i.e. at any level or even as an indexed group. It cannot be used to access MU/PEfields of a database view. A multidimensional array may have a mixture of constant and variable bounds.
Example:
DEFINE DATA LOCAL 1 #XARR1 (A5/1:*) /* lower bound is fixed at 1, upper bound is variable 1 #XARR2 (A5/*) /* shortcut for (A5/1:*) 1 #XARR3 (A5/*:100) /* lower bound is variable, upper bound is fixed at 100 1 #XARR4 (A5/1:10,1:*) /* 1st dimension has a fixed index range with (1:10) ENDDEFINE /* 2nd dimension has fixed lower bound 1 and variable upper bound
Occurrences of an Xarray must be allocated explicitly before they can
be accessed. To increase or decrease the number of occurrences of a dimension,
the statements EXPAND
,
RESIZE
and
REDUCE
may be
used.
However, the number of dimensions of the Xarray (1, 2 or 3 dimensions) cannot be changed.
Example:
DEFINE DATA LOCAL 1 #XARR(I4/10:*) ENDDEFINE EXPAND ARRAY #XARR TO (10:10000) /* #XARR(10) to #XARR(10000) are accessible WRITE *LBOUND(#XARR) /* is 10 *UBOUND(#XARR) /* is 10000 *OCCURRENCE(#XARR) /* is 9991 #XARR(*) := 4711 /* same as #XARR(10:10000) := 4711 /* resize array from current lower bound=10 to upper bound =1000 RESIZE ARRAY #XARR TO (*:1000) /* #XARR(10) to #XARR(1000) are accessible /* #XARR(1001) to #XARR(10000) are released WRITE *LBOUND(#XARR) /* is 10 *UBOUND(#XARR) /* is 1000 *OCCURRENCE(#XARR) /* is 991 /* release all occurrences REDUCE ARRAY #XARR TO 0 WRITE *OCCURRENCE(#XARR) /* is 0
If you want to increase or decrease occurrences of Xgroup arrays, you must distinguish between independent and dependent dimensions.
A dimension which is specified directly (not inherited) for an X(group) array is independent.
A dimension which is not specified directly, but inherited for an array is dependent.
Only independent dimensions of an Xarray can be changed in the
statements EXPAND
,
RESIZE
and
REDUCE
; dependent
dimensions must be changed using the name of the corresponding Xgroup array
which owns this dimension as independent dimension.
DEFINE DATA LOCAL 1 #XGROUPARR1(1:*) /* (1:*) 2 #XARR1 (I4) /* (1:*) 2 #XARR2 (I4/2:*) /* (1:*,2:*) 2 #XGROUPARR2 /* (1:*) 3 #XARR3 (I4) /* (1:*) 3 #XARR4 (I4/3:*) /* (1:*,3:*) 3 #XARR5 (I4/4:*, 5:*) /* (1:*,4:*,5:*) ENDDEFINE
The following table shows whether the dimensions in the above program are independent or dependent.
Name  Dependent Dimension  Independent Dimension 

#XGROUPARR1 
(1:*) 

#XARR1 
(1:*) 

#XARR2 
(1:*) 
(2:*) 
#XGROUPARR2 
(1:*) 

#XARR3 
(1:*) 

#XARR4 
(1:*) 
(3:*) 
#XARR5 
(1:*) 
(4:*,5:*) 
The only index notation permitted for a dependent dimension is either a single asterisk (*), a range defined with asterisks (*:*) or the index bounds defined.
This is to indicate that the bounds of the dependent dimension must be kept as they are and cannot be changed.
The occurrences of the dependent dimensions can only be changed by manipulating the corresponding array groups.
EXPAND ARRAY #XGROUPARR1 TO (1:11) /* #XARR1(1:11) are allocated /* #XARR3(1:11) are allocated EXPAND ARRAY #XARR2 TO (*:*, 2:12) /* #XARR2(1:11, 2:12) are allocated EXPAND ARRAY #XARR2 TO (1:*, 2:12) /* same as before EXPAND ARRAY #XARR2 TO (* , 2:12) /* same as before EXPAND ARRAY #XARR4 TO (*:*, 3:13) /* #XARR4(1:11, 3:13) are allocated EXPAND ARRAY #XARR5 TO (*:*, 4:14, 5:15) /* #XARR5(1:11, 4:14, 5:15) are allocated
The EXPAND
statements may be coded in an arbitrary
order.
The following use of the EXPAND
statement is not allowed,
since the arrays only have dependent dimensions.
EXPAND ARRAY #XARR1 TO ... EXPAND ARRAY #XGROUPARR2 TO ... EXPAND ARRAY #XARR3 TO ...
The occurrences of an Xarray must be allocated by an
EXPAND
or
RESIZE
statement
before they can be accessed.
As a general rule, an attempt to address a nonexistent Xarray
occurrence leads to a runtime error. In some statements, however, the access to
a nonmaterialized Xarray field does not cause an error situation if all
occurrences of an Xarray are referenced using the complete range notation, for
example: #XARR(*)
. This applies to
parameters used in a CALL
statement,
parameters used in the statements CALLNAT
,
PERFORM
or OPEN DIALOG
, if defined as optional
parameters,
source fields used in a COMPRESS
statement,
output fields supplied in a PRINT
statement,
fields referenced in a RESET
statement.
If individual occurrences of a nonmaterialized Xarray are referenced in one of these statements, a corresponding error message is issued.
Example:
DEFINE DATA LOCAL 1 #XARR (A10/1:*) /* Xarray only defined, but not allocated ENDDEFINE RESET #XARR(*) /* no error, because complete field referenced with (*) RESET #XARR(1:3) /* runtime error, because individual occurrences (1:3) are referenced END
The asterisk (*) notation in an array reference stands for the complete
range of a dimension. If the array is an Xarray, the asterisk is the index
range of the currently allocated lower and upper bound values, which are
determined by the system variables *LBOUND
and *UBOUND
.
Xarrays that are used as parameters are treated in the same way as constant arrays with regard to the verification of the following:
format,
length,
dimension or
number of occurrences.
In addition, Xarray parameters can also change the number of
occurrences using the statement RESIZE
,
REDUCE
or
EXPAND
. The question
if a resize of an Xarray parameter is permitted depends on three factors:
the type of parameter transfer used, that is by reference or by value,
the definition of the caller or parameter Xarray, and
the type of Xarray range being passed on (complete range or subrange).
The following tables demonstrate when an
EXPAND
,
RESIZE
or
REDUCE
statement can
be applied to an Xarray parameter.
Caller  Parameter  

Static  Variable (1:V)  XArray  
Static  no  no  yes 
Xarray subrange, for example:
CALLNAT...#XA(1:5) 
no  no  yes 
Xarray complete range, for example:
CALLNAT...#XA(*) 
no  no  yes 
Caller  Parameter  

Static  Variable (1:V)  XArray with a fixed lower bound, e.g.
DEFINE DATA PARAMETER 1 #PX (A10/1:*) 
XArray with a fixed upper bound, e.g.
DEFINE DATA PARAMETER 1 #PX (A10/*:1) 

Static  no  no  no  no 
Xarray subrange, for example:
CALLNAT...#XA(1:5) 
no  no  no  no 
XArray with a fixed lower bound, complete range, for example:
DEFINE DATA LOCAL 1 #XA(A10/1:*) ... CALLNAT...#XA(*) 
no  no  yes  no 
XArray with a fixed upper bound, complete range, for example:
DEFINE DATA LOCAL 1 #XA(A10/*:1) ... CALLNAT...#XA(*) 
no  no  no  yes 
The declaration of an Xgroup array implies that each element of the
group will have the same values for upper boundary and lower boundary.
Therefore, the number of occurrences of dependent dimensions of fields of an
Xgroup array can only be changed when the group name of the Xgroup array is
given with a RESIZE
,
REDUCE
or
EXPAND
statement (see
Storage Management of XGroup
Arrays above).
Members of Xgroup arrays may be transferred as parameters to Xgroup
arrays defined in a parameter data area. The group structures of the caller and
the callee need not necessarily be identical. A RESIZE
,
REDUCE
or EXPAND
done by the callee is only possible
as far as the Xgroup array of the caller stays consistent.
Program:
DEFINE DATA LOCAL 1 #XGROUPARR1(1:*) /* (1:*) 2 #XARR1 (I4) /* (1:*) 2 #XARR2 (I4) /* (1:*) 1 #XGROUPARR2(1:*) /* (1:*) 2 #XARR3 (I4) /* (1:*) 2 #XARR4 (I4) /* (1:*) ENDDEFINE ... CALLNAT ... #XARR1(*) #XARR4(*) ... END
Subprogram:
DEFINE DATA PARAMETER 1 #XGROUPARR(1:*) /* (1:*) 2 #XPAR1 (I4) /* (1:*) 2 #XPAR2 (I4) /* (1:*) ENDDEFINE ... RESIZE ARRAY #XGROUPARR to (1:5) ... END
The RESIZE
statement in the subprogram is not possible. It
would result in an inconsistent number of occurrences of the fields defined in
the Xgroup arrays of the program.
An Xarray of dynamic variables may be allocated by first specifying the
number of occurrences using the EXPAND
statement and then
assigning a value to the previously allocated array occurrences.
DEFINE DATA LOCAL 1 #XARRAY(A/1:*) DYNAMIC ENDDEFINE EXPAND ARRAY #XARRAY TO (1:10) /* allocate #XARRAY(1) to #XARRAY(10) with zero length. /* *LENGTH(#XARRAY(1:10)) is zero #XARRAY(*) := 'abc' /* #XARRAY(1:10) contains 'abc', /* *LENGTH(#XARRAY(1:10)) is 3 EXPAND ARRAY #XARRAY TO (1:20) /* allocate #XARRAY(11) to #XARRAY(20) with zero length /* *LENGTH(#XARRAY(11:20)) is zero #XARRAY(11:20) := 'def' /* #XARRAY(11:20) contains 'def' /* *LENGTH(#XARRAY(11:20)) is 3
The system variables *LBOUND
and *UBOUND
contain the current lower and upper bound of an array for the specified
dimension(s): (1,2 or 3).
If no occurrences of an Xarray have been allocated, the access to
*LBOUND
or *UBOUND
is
undefined for the variable index bounds, that is, for the boundaries that are
represented by an asterisk (*) character in the index definition, and leads to
a runtime error. In order to avoid a runtime error, the system variable
*OCCURRENCE
may be used to check against zero occurrences before
*LBOUND
or *UBOUND
is
evaluated:
Example:
IF *OCCURRENCE (#A) NE 0 AND *UBOUND(#A) < 100 THEN ...