Software Engineers Handbook/Language Dictionary/PLI/arrays

Note: This article requires basic knowledge of PL/I which can be found in Software Engineers Handbook/Language Dictionary/PLI.

Declaring Arrays
Simple arrays may be declared with the following syntax:

DCL  name_of_array   (               higher_bound )   type_of_elements; or DCL  name_of_array   ( lower_bound : higher_bound )   type_of_elements;

If lower bound is omitted it will get the default value 1.

example: proc options ( main ); dcl  array_A (  5)   char (03);   /* array_A has 5 elements with index 1 to 5 */ dcl  array_B (0:5)   char (03);   /* array_B has 6 elements with index 0 to 5 */ array_A ( 1 ) = 4711;          /* fill first element of array_A ... */   array_B ( 0 ) = array_A ( 1 );  /* ... and copy its value to first element of array_B */ end example; Multi-dimension array are declared by separating the dimensions with commas.

example: proc options ( main ); dcl  matrix ( 2, 6:7 )   bin fixed (31); /* defines a 2-dimensional array of 4 elements: matrix ( 1, 6 ) , matrix ( 1 , 7 ) , */ /*                                             matrix ( 2, 6 ) , matrix ( 2 , 7 )   */ matrix ( 1, 6 ) = 123;  /* store number into first matrix element */ matrix ( 2, 7 ) = 456;  /* store number into  last matrix element */ end example;

Elements of an array may not only be simple types like numbers, strings or pointers but also entry variables, files, structures ...

example: proc options ( main ); dcl  1 month ( 12 ),   /* means January ... December */ 2 income  dec fixed ( 7, 2 ), 2 outgo   dec fixed ( 7, 2 ); month ( 1 ). income = 1234.56;  /* store income-value of January  */ month. income ( 2 ) = 2345.67;  /* store income-value of February */ month ( 3 ). outgo = 3456.78;   /* store  outgo-value of March    */ month. outgo ( 4 ) = 4567.89;   /* store  outgo-value of April    */ end example; example: proc options ( main ); dcl  1 year ( 1999 : 2019 ), 2 month ( 12 ), 3 value ( 3, 3 )  bin fixed (15); /* all of the following statements are equal */ year ( 2009 ). month ( 9 ). value ( 1, 2 ) = 32767; year. month ( 2009, 9 ). value ( 1, 2 )  = 32767; year. month. value ( 2009, 9 , 1 , 2 )    = 32767; year. month ( 2009, 9 , 1 , 2 ). value    = 32767; year ( 2009, 9 , 1 , 2 ). month. value    = 32767; end example;

Initialising an Array
An array may be initialised by the use of the INITIAL (abbr: INIT) attribute. Initialisation has to be done for every array element individually. To specify a single element to be uninitialised an asterisk may be used.

In the examples below program left will be equivalent to program right.

left: proc options ( main );                   right: proc options ( main ); dcl  A ( 4 )   char (03)                       dcl   A ( 4 )   char (03); init ( 'ABC', * , 'XYZ' ); A ( 1 ) = 'ABC'; A ( 3 ) = 'XYZ'; end left;                                      end right;

For making it more comfortable to initialise a huge array an iteration-factor (prefix "(n)" meaning: use following value(s) n-times ) may be used.

left: proc options ( main );                          right: proc options ( main ); dcl  A ( 2, 3 )   bin fixed (15)                     dcl   A ( 2 , 3 )   bin fixed (15); init ( (2)5, (2)* , (2)6 ); A ( 2, 1 ) = 5; A ( 2, 2 ) = 5; /* A ( 2, 3 ) will be left uninitialised */ /* A ( 3, 1 ) will be left uninitialised */ A ( 3, 2 ) = 6; A ( 3, 3 ) = 6; end left;                                             end right; left: proc options ( main );                          right: proc options ( main ); dcl  A ( 2, 3 )   bin fixed (15)                     dcl   A ( 2 , 3 )   bin fixed (15); init ( (2)(-3,7), 99 ); A ( 2, 1 ) = -3; A ( 2, 2 ) = 7; A ( 2, 3 ) = -3; A ( 3, 1 ) = 7; A ( 3, 2 ) = 99; end left;                                             end right;

Be aware: PL/I also offers iteration factors for strings, e.g. the expression "(4)X" is equivalent to "XXXX". So if an array of strings is initialised it must be clear whether an iteration factor is for the string or for the initialisation.

init ( (2) (3)  'X'   )   ... means  use twice:     'XXX' init (    (6)   'X'   )   ... means  use once-only: 'XXXXXX' init (    (6) ( 'X' ) )   ... means  use 6 times:   'X'

Evaluation of Array Expressions

 * An array expression may contain both arrays and single values
 * All arrays in the expression must have the same structure, i.e. they must have the same number of dimensions, and corresponding dimensions must have identical bounds
 * The result of the expression has the same structure as the contained array(s)
 * The result of the expression may be assigned to an array variable having the same structure

In the examples below program left will be equivalent to program right.

left: proc options ( main );           right: proc options ( main ); dcl  A (2,6:7)   bin fixed (15);       dcl   A (2,6:7)   bin fixed (15); dcl  B (2,6:7)   bin fixed (15);       dcl   B (2,6:7)   bin fixed (15); dcl  C (2,6:7)   bin fixed (15);       dcl   B (2,6:7)   bin fixed (15); /* fill variable B */                  /* fill variable B */ /* fill variable C */                  /* fill variable C */ A = B + C * 5;                         A ( 1, 6 ) = B ( 1 , 6 ) + C ( 1 , 6 ) * 5; A ( 1, 7 ) = B ( 1 , 7 ) + C ( 1 , 7 ) * 5; A ( 2, 6 ) = B ( 2 , 6 ) + C ( 2 , 6 ) * 5; A ( 2, 7 ) = B ( 2 , 7 ) + C ( 2 , 7 ) * 5; end left;                              end right;

All operations performed on arrays are done in an element-by-element-way, in right-to-left-dimension order.

left: proc options ( main );                right: proc options ( main ); dcl  A (2,2)   init ( 1, 2, 10, 50 );       dcl   A (2,2)   init ( 1, 2, 10, 50 ); A = A + A ( 2, 1 );                        A ( 1 , 1 ) = A ( 1 , 1 ) +  A ( 2 , 1 );   /* =  1 + 10 = 11 */ A ( 1, 2 ) = A ( 1 , 2 ) + A ( 2 , 1 );   /* =  2 + 10 = 11 */ A ( 2, 1 ) = A ( 2 , 1 ) + A ( 2 , 1 );   /* = 10 + 10 = 20 */ A ( 2, 2 ) = A ( 2 , 2 ) + A ( 2 , 1 );   /* = 50 + 20 = 70 */ end left;                                   end right;

Cross Sections of Arrays Using Asterisks
Using asterisk notation a cross section of an array may be referred. The asterisk specifies that the entire extent for this dimension will be used.

If an array is declared as   dcl   A ( 2, 3 )   char (06); the reference A ( *, 3 ) refers to a 1-dimensional array containing the elements A ( 1, 3 ) and A ( 2 , 3 ), the reference A ( 1, * ) refers to a 1-dimensional array containing the elements A ( 1, 1 ) and A ( 1 , 2 ) and A ( 1 , 3 ).

In the examples below program left will be equivalent to program right.

left: proc options ( main );           right: proc options ( main ); dcl  A ( 2, 2 )   char (10);          dcl   A ( 2 , 2 )   char (10); dcl  B ( 2, 2 )   char (10);          dcl   B ( 2 , 2 )   char (10); A ( *, * ) = 'hello PL/I';            A = 'hello PL/I';   /* fill all elements of A */ B ( *, 1 ) = A ( 2 , * );             B ( 1 , 1 ) = A ( 2 , 1 ); B ( 2, 1 ) = A ( 2 , 2 ); end left;                              end right;

Re-Defining an Existing Array
A new declared array may be mapped to an existing "old" array by using the DEFINED (abbr: DEF) attribute.

In the examples below program left will be equivalent to program right.

left: proc options ( main );           right: proc options ( main ); dcl  A ( 8, 8 )   char (10);          dcl   A ( 8 , 8 )   char (10); dcl  B ( 6, 6 )   char (10)   defined A;                                         dcl   C ( 4 )       char (10)   def A ( * , 2 ); A ( 6, 6 ) = 'hello PL/I';            B ( 6 , 6 ) = 'hello PL/I'; A ( 4, 2 ) = 'hello PL/I';            C ( 4 )     = 'hello PL/I'; end left;                              end right;

To refer to designated elements of the old array the declaration of the new array may contain iSUB elements.

iSUB means: Whenever an access to the new array will be done the i-th index of this refer will be used to calculate the index(es) of the old array.

In the examples below program left will be equivalent to program right.

left: proc options ( main );           right: proc options ( main ); dcl  A ( 8, 8 )   char (10);          dcl   A          ( 8 , 8 )   char (10); dcl  transposed ( 8, 8 )   char (10)   DEF A ( 2sub , 1sub ); dcl  centered   ( 4, 4 )   char (10)   DEF A ( 1sub + 2 , 2sub + 2 ); dcl  diagonal   ( 8 )       char (10)   DEF A ( 1sub, 1sub ); A ( 2, 5 ) = 'hello PL/I';            transposed ( 5 , 2 ) = 'hello PL/I';   /* swap indexes     */ A ( 3, 6 ) = 'hello PL/I';            centered   ( 1 , 4 ) = 'hello PL/I';   /* increase indexes */ A ( 7, 7 ) = 'hello PL/I';            diagonal   ( 7 )     = 'hello PL/I';   /* use index twice  */ end left;                              end right;

Connected and Unconnected Storage
Arrays will be stored connected in an element-by-element-way, in right-to-left-dimension order.

dcl  A ( 2, 2 , 2 )   char (10); allocates adjacent storage in the following order: +---+---+---+---+---+---+---+---+   | A (1,1,1) | A (1,1,2) | A (1,2,1) | A (1,2,2) | A (2,1,1) | A (2,1,2) | A (2,2,1) | A (2,2,2) | +---+---+---+---+---+---+---+---+

References to a cross section of an array may refer to unconnected storage.

dcl A ( 2, 2 )  will allocates storage in the following order: +-+-+-+-+   | A ( 1, 1 ) | A ( 1 , 2 ) | A ( 2 , 1 ) | A ( 2 , 2 ) | +-+-+-+-+ the reference  A ( 1, * )   refers to connected storage. +-+-+   | A ( 1, 1 ) | A ( 1 , 2 ) | +-+-+ the reference  A ( *, 1 )   refers to unconnected storage. +-+ - - - - - - +-+   | A ( 1, 1 ) |     gap     | A ( 2 , 1 ) | +-+ - - - - - - +-+

References to a structured element inside an array will refer to unconnected storage.

'''dcl 1 A ( 2 ), 2 B ... ,         2 C ... ;  will allocates storage in the following order: +-+-+-+-+   | A ( 1 ). B | A ( 1 ). C | A ( 2 ). B | A ( 2 ). C | +-+-+-+-+ the reference  '''A. B  refers to unconnected''' storage. +-+ - - - - - - +-+   | A ( 1 ). B |    gap     | A ( 2 ). B | +-+ - - - - - - +-+

References to defined array may refer to unconnected storage.

dcl A ( 2, 2 )  will allocates storage in the following order: +-+-+-+-+   | A ( 1, 1 ) | A ( 1 , 2 ) | A ( 2 , 1 ) | A ( 2 , 2 ) | +-+-+-+-+ dcl B ( 2 ) def A ( 1sub, 1sub )  refers to unconnected storage. +-+ - - - - - - + - - - - - - +-+   | B ( 1 )     |                           | B ( 2 )     | | refers to  |            gap            | refers to   | | A ( 1, 1 ) |                          | A ( 2 , 2 ) | +-+ - - - - - - + - - - - - - +-+

Builtin Array Functions
Common functions: The array A must not be an array of structures.
 * LBOUND ( A, i ) returns the lower bound of the i-th dimension of array A
 * HBOUND ( A, i ) returns the higher bound of the i-th dimension of array A
 * DIM ( A, i ) returns the extent of the i-th dimension of array A, i.e. DIM ( A , i ) = HBOUND ( A , i ) - LBOUND ( A , i ) + 1

example: proc options ( main ); dcl  matrix ( 15, -4:4 ); put skip list ( LBOUND ( matrix, 1 ) );  /* output:  1 */ put skip list ( HBOUND ( matrix, 1 ) );  /* output: 15 */ put skip list (   DIM ( matrix, 1 ) );   /* output: 15 */ put skip list ( LBOUND ( matrix, 2 ) );  /* output: -4 */ put skip list ( HBOUND ( matrix, 2 ) );  /* output:  4 */ put skip list (   DIM ( matrix, 2 ) );   /* output:  9 */ end example;

Mathematical functions:
 * SUM ( A ) returns the sum of all the elements in array A
 * PROD ( A ) returns the product of all the elements in array A

example: proc options ( main ); dcl  A ( 4 )   bin fixed (31)   init ( 1, 2 , 3 , 4 ); put skip list ( SUM ( A ) );   /* output: 10 = 1 + 2 + 3 + 4 */ put skip list ( PROD ( A ) );  /* output: 24 = 1 &times; 2 &times; 3 &times; 4 */ end example;

Logical functions: The builtin functions ANY and ALL requires an array of bit strings as argument. They will be explained in Software_Engineers_Handbook/Language_Dictionary/PLI/bit_strings.

Restrictions
In PL/I for MVS arrays are restricted to the following limits:
 * The maximum number of dimensions is 15
 * The minimum lower bound is - 2,147,483,648 = - 231
 * The maximum higher bound is + 2,147,483,647 = + 231 - 1
 * The maximum memory size is 2,147,483,648 bytes = 231 bytes