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.