Part B--Records

9.7 Declaring and Assigning to Records

The discussions of sections 1.6.3 and 9.1 explored the idea of modeling data that by its very nature consists of items of different types aggregated together into a single structure. For instance, one might wish to define an aggregate, or record:

traveller =
  name
  home address
  airline
  flight number
  arrival
  departure
  luggage
A Modula-2 record is a data abstraction designed to allow for aggregates of various types of related data named by a single identifier.

Records are examples of what mathematicians call cross products. A cross product of two sets is the set of ordered pairs with first coordinate from the first set, second from the second set, thus:

A * B = { (a, b) | a A and b B}

For instance,

{2, 4} * { 1, 6} = {(2, 1), (2, 6), (4, 1), (4, 6)}

In the case of records, the cross product is done with two or more (usually different) data types. That is, one expresses a structure struct that is

REAL * CARDINAL * BOOLEAN

as, say

TYPE
  struct = 
    RECORD
      salary : REAL;
      days : CARDINAL;
      male : BOOLEAN;
    END;

where both the overall kind of structure (type) and the individual parts have names.

Consider, for instance, the representation of a person as a record where the abstraction (the program data as opposed to the actual person) consists of a last name, first name, birthdate, sex, identity number, marital status, and a statement about their role on a university campus. Of these, one could also in turn structure a record for dates that consists of a year, a month, and a day. Here are some declarations to illustrate the Modula-2 syntax:

TYPE
  MonthType = (Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sept, Oct, Nov, Dec);
  Name = ARRAY [0 .. 20] OF CHAR;
  Role = (freshman, sophomore, junior, senior, professor, administrator, maintenance, associate, assistant, secretary);

  Date =
    RECORD
      year : CARDINAL;
      month : MonthType;
      day : [1 .. 31];   (* semicolon optional *)
    END;    (* of the record Date *)

  Person =
    RECORD
      lastname, firstname : Name;
      birth : Date;
      male : BOOLEAN;
      idnumber : CARDINAL;
      married : BOOLEAN;
      status : Role;
    END;  (* of the record Person *)

VAR
  student, faculty : Person;

NOTES: 1. RECORD is a reserved word, and each RECORD declaration must have an associated END.

2. The individual parts of a record are called fields.

3. A record field can be of any type, including an array, a user-defined type, or another record.

4. In the original definition of Modula-2, a function procedure could not return a RECORD as its result. Newer versions (including ISO standard ones) allow this. If this restriction does exist, it will be noted later that there may be a way around it.

5. There will probably be some implementation dependent maximum record size, though this is not likely to impact on the programs of a beginner.

The individual fields in each record each have their own identifier, and each is referred to by a qualified identifier that includes the record name itself. The following statements assign the fields of the above record:

student.lastname := "Hacker";
student.firstname := "Nellie";
student.birth.year := 1965;
student.birth.month := Feb;
student.birth.day := 12;
student.male := FALSE;
student.idnumber := 46725;
student.married := FALSE;
student.status := freshman;

In a similar way, one could assign the fields of a record representing a faculty member, except that the last one could read, say:

faculty.status := associate;

One could also define the structure of name and birth within the declaration of person, writing:

TYPE
  Person =
    RECORD
      lastname, firstname : Name;
      birth =
        RECORD
          year : CARDINAL;
          month : MonthType;
          day : [1 .. 31];
        END;    (* of the sub-record Date *)
      male : BOOLEAN;
      idnumber : CARDINAL;
      married : BOOLEAN;
      status : Role;
    END;  (* of the record Person *)

However, it is better programming practice to employ separate type declarations for each structure, rather than bury structures without type names inside another one (anonymous types). Once Date is properly declared as a type, it can be used in a variety of other declarations, rather than having to write out its structure every time. Such natural abstractions should always be made explicit in the code.


Contents