Part B--Intermediate (Structured) Data Issues

11.6 Structure Constructors

Recall from Chapter 9 that it is possible to construct sets from literals:

  charSet1 := CharSet {'A' .. 'Z'};
  digits := DigitType {0 .. 2};

and that

The Modula-2 notation Type {list} is said to be a constructor.

It is also possible to construct specific arrays and records from literals in a similar fashion, as shown in the following two sections.

11.6.1 Array Constructors

Suppose a program has the declarations:

TYPE
  Vector = ARRAY [1..10] OF CARDINAL;
VAR
  v1 : Vector;

In order to initialize such an array so that its components were, say, the values 1 through 10, one can write a loop, as shown earlier in the text:

FOR count := 1 TO 10
  DO
    v1 [count] := count
  END;

However the same goal may be achieved using the constructor notation as follows.

v1 := Vector {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

If some of the components are to have the same value, repetition is shown using BY. That is:

v1 := Vector {1, 1, 1, 4, 4, 6, 7, 7, 7, 7};

is equivalent to:

v1 := Vector {1 BY 3, 4 BY 2, 6, 7 BY 4};

and all the components could be initialized to, say, zero using simply:

v1 := Vector {0 BY 10};

Note that all components must receive a value, so that

v1 := Vector {0 BY 9};

will cause the compiler to report an error. In addition, the values employed may be expressions, including the returns from functions, this if one had:

PROCEDURE NextCount () : CARDINAL;
BEGIN
  INC (count);
  RETURN count;
END NextCount;

then the constants 1 through 10 could be entered in the vector by

  count := 0;
  v1 := Vector {NextCount() BY 10};

although this use of side-effects on a global variable is not generally a good idea.

Similar considerations apply to other arrays, so that:

TYPE
  String80 = ARRAY [0..79] OF CHAR;
  RealVector = ARRAY [1..10] OF REAL;

VAR
  str : String80;
  rvect : RealVector;

could be initialized by such calls as:

chr := "o";
str := String80{"H", "e", "l" BY 2, chr, 0C BY 75};
rvect := RealVector {0.0 BY 10};

It is also quite proper to construct a constant of one of these types:

CONST
  NullStr = NameString {0C BY 80};

If the array is two dimensional, it is treated as an ARRAY OF ARRAY and the constructor notation is appropriately nested. The following declarations and statements are legal:

TYPE
  RowType = ARRAY [1..4] OF INTEGER;
  Array34 = ARRAY [1..3], [1..4] OF INTEGER;
  Array3R = ARRAY [1..3] OF RowType;  (* last two have same structure *)

VAR
  row : RowType;
  array1 : Array34;
  array2 : Array3R;

  array1 := Array34 { {1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12} };
  array1 := Array34 { {1, 2, 3, 4} BY 3 }; (* three rows the same *)
  array2 := Array3R {RowType{1, 2, 3, 4} BY 3};  (* same result *)
  array2 := Array3R { {0 BY 4} BY 3 };  (* all 12 entries are 0 *)
  row := RowType {1 BY 4};
  array2 := Array3R { row BY 3 };  (* all 12 entries are 1 *)

Similar considerations apply if three or more dimensions are employed.

11.6.2 Record Constructors

Records may also have constructed values, and this is particularly useful for initialization purposes. As arrays may have arrays as their components, so also records may have nested records, and therefore nested constructors. Given the declarations:

TYPE
  NameString = ARRAY [0..50] OF CHAR;
  Month = (Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec);
  Date = 
    RECORD
      year: CARDINAL;
      month : Month;
      day : CARDINAL;
    END;
  Person  =
    RECORD
      name : NameString;
      birthdate : Date;
    END;
  Group = ARRAY [1..100] OF Person;

CONST
  startDate = Date {1, Jan, 1};
  
VAR
  moniker : NameString;  
  da : Date;
  nullPerson, Joe : Person;
  class : Group;

the following are legal:

  moniker := "Josephine";
  da := Date {1901, Jan, 4};
  nullPerson := Person {"", {1994, Oct, 15} };
  Joe := Person {moniker, da };
  Joe := Person {"Joe", da };
  class := Group {nullPerson BY 100};

Observe that since the assignments to items of type Person are not assigning via constructors to the arrays, ordinary literal strings will do. This is certainly easier than:

  Joe := Person { {"J","o","e", 0C BY 48 }, da };

where each character must be accounted for individually.


Contents