Chapter 11 RECORDS PREREQUISITES FOR THIS MATERIAL ______________________________________________________________ In order to do a profitable study of this material, you will need a good understanding of all of the material in Part I. The material concerning the scalar type from chapter 11 is also needed. We come to the grandaddy of all data ================ structures in Modula-2, the record. A SMALLREC.MOD record is composed of a number of ================ variables any of which can be of any predefined data type, including other records. Rather than spend time trying to define a record in detail, lets go right to the first example program, SMALLREC.MOD. This is a program using nonsense data that will illustrate the use of a record. A VERY SIMPLE RECORD ______________________________________________________________ There is only one entry in the type declaration part of the program, namely the record identified by Description. The record is composed of three fields, the Year, Model, and Engine variables. Notice that the three fields are each of a different type, indicating that the record can be of mixed types. You have a complete example of the way a record type is defined before you. It is composed of the identifier Description, the reserved word RECORD, the list of elements, and followed by END;. Notice that this only defines a type, it does not define any variables. That is done in the var declaration where the variable Truck is defined as a record variable of type Description. The variable Truck has three components, Year, Model, and Engine, and any or all of these components can be used to store data pertaining to the variable named Truck. An array of 10 Cars is also defined in line 13 for later use. In order to assign values to the various fields, the variable name is followed by the sub-field with a separating period. Keep in mind that Truck is a complete record containing three variables, and to assign or use one of the variables, you must designate which sub-field you are interested in. Examine the program where the three fields are assigned meaningless data for illustration in lines 18 through 20. Notice that each of the components is treated as a simple variable and each component is assigned some nonsense data for illustration. Study the dot notation carefully here because it will be used frequently in Modula-2 programs. 11-1 Chapter 11 - Records The loop in lines 22 through 26 is used to assign nonsense data to all of the fields of the array of record variables named Cars. The Year field is assigned an integer number varying with the subscript, all Model fields are assigned the name Duesenburg, and all Engine variables are assigned the value V8. In order to further illustrate that there are actually 30 variables in use here, a few are changed at random in the next few statements, being very careful to maintain the required types as defined in the type declaration part of the program. The Truck variable is printed out for illustration and finally, all ten composite variables named Cars, consisting of 30 actual variables in a logical grouping are printed out using the same "var.subfield" notation described above. If the preceding description of a record is not clear in your mind, review it very carefully. It's a very important concept in Modula-2, and you won't have a hope of a chance of understanding the next example until this one is clear. Keep in mind that a record is used to group some number of possibly different types of data that are related to each other in some way. A SUPER RECORD ______________________________________________________________ Examine the example file BIGREC.MOD for a ================ very interesting record. First we have a BIGREC.MOD constant defined. Ignore it for the ================ moment, we will come back to it later. Within the type declaration we have three records defined, and upon close examination, you will notice that the first two records are included as part of the definition of the third record. The record identified as Person actually contains 8 variable definitions, three within the FullName record, two of its own, and three within the Date record. Once again, this is a type declaration and does not actually define any variables. The actual variables will be defined in the var part of the program. The var part of the program defines some variables beginning with the array of Friend containing 50 (because of the constant definition in the const part) records of Person. Since Person defines 8 fields, we have now defined 8 times 50 = 400 separate and distinct variables. Each of the 400 separate variables has its own type associated with it, and the compiler will generate an error if you try to assign any of those variables the wrong type of data. Since Person is a type definition, it can be used to define more than one variable, and in fact it is used again to define three more records, Self, Mother, and Father. These three records are each composed of 8 variables, so we have 24 more variables 11-2 Chapter 11 - Records which we can manipulate within the program. Finally we have the variable Index defined as a simple cardinal type variable. Notice that if we desired, we could also define a variable of type FullName composed of 3 simple variables. HOW TO MANIPULATE ALL OF THAT DATA ______________________________________________________________ In the program we begin by assigning data to all of the fields of Self in lines 30 through 42. Examining the first three statements of the main program, we see the construction we learned in the last example program being used, namely the period between descriptor fields. The main record is named Self, and we are interested in the first part of it, namely the Name part of the person record. Since the Name part of the person record is itself composed of three parts, we must designate which part of it we are interested in. The name Self.Name.FirstName is the complete description of the first name of Self and is the first assignment statement which is assigned the name of Charley. The next two fields are handled in the same way and should be self explanatory. WHAT IS THE WITH STATEMENT? ______________________________________________________________ Continuing on to the fourth field, the City, there are only two levels required because City is not another record definition. The fourth field is therefore completely defined by Self.City. Notice the "WITH Self DO" statement. This is a shorthand notation used with record definitions to simplify coding used in the same manner as in Pascal. From the next statement to the matching end statement in line 42, any variables within the Self record are used as though they had a Self. in front of them. It greatly simplifies coding to be able to omit the leading identifier within the with section of code. You will see that City, and State, are easily assigned values without further reference to the Self variable. When we get to the Day part of the birthday, we are back to three levels and the complete definition is Self.Birthday.Day but once again, the Self part is taken care of automatically because we are still within the "WITH Self DO" area. To illustrate the with statement further, another is introduced, "WITH Birthday DO", which takes effect until the end statement. Within this area both leading identifiers are handled automatically to simplify coding, and Month is equivalent to writing Self.Birthday.Month if both with statements were removed. You may be wondering how many levels of nesting are allowed in record definitions. There doesn't appear to be a limit according to the Modula-2 definition, but we do get a hint at how far it is possible to go. In most 11-3 Chapter 11 - Records implementations of Modula-2, you are allowed to have with statements nested to nine levels, and it would be worthless to nest with statements deeper than the level of record nesting. Any program requiring more levels than nine is probably far beyond the scope of your programming ability, and mine, for a long time. After assigning a value to the year, the entire record of Self is defined, all eight variables. SUPER-ASSIGNMENT STATEMENTS ______________________________________________________________ The next statement, Mother := Self; is very interesting. Since both of these are records, both are the same type of record, and both therefore contain 8 variables, Modula-2 is smart enough to recognize that, and assign all eight values contained in Self to the corresponding variables of Mother. So after one statement, Mother is completely defined. The next statement assigns the same values to the eight respective fields of Father, and the loop in lines 47 through 50 assigns all 50 Friend variables the same data. We have therefore generated 400 + 24 = 424 separate pieces of data so far in this program. We could print it all out, but since it is nonsense data, it would only waste time and paper. Lines 51 through 56 write out three sample pieces of the data for your inspection. WHAT GOOD IS ALL OF THIS ______________________________________________________________ It should be obvious to you that what this program does, even though the data is nonsense, appears to be the beginning of a database management program, which indeed it is. It is a crude beginning, and has a long way to go to be useful, but you should see a seed for a useful program. Now to go back to the const as promised. The number of friends was defined as 50 and used for the size of the array and in the assignment loop near the end of the program. You can now edit this number and see how big this database can become on your computer. Your compiler should be capable of storing about 1000 records even within the smallest model available on any compiler. If your compiler uses a larger memory model, you will be able to store significantly more records. See how big you can make the number of friends before you get the memory overflow message. Keep the number in mind because when we get to the chapter on Pointers and Dynamic Allocation, you should see a marked increase in allowable size, especially if you have a large amount of RAM 11-4 Chapter 11 - Records installed in your computer. If your compiler uses a large memory model, you won't see an increase in size but it will be an interesting exercise anyway. A VARIANT RECORD ______________________________________________________________ If any part of this chapter is still unclear, it would be good for you to go back and review it at this time. The next example will really tax your mind to completely understand it, especially if the prior material is not clear. Examine the program VARREC.MOD for an ================ example of a program with a variant record VARREC.MOD definition. In this example, we first ================ define a scalar type, namely KindOfVehicle for use within the record. Then we have a record defining Vehicle, intended to define several different types of vehicles, each with different kinds of data. It would be possible to define all variables for all types of vehicles, but it would be a waste of storage space to define the number of tires for a boat, or the number of propeller blades used on a car or truck. The variant record lets us define the data precisely for each vehicle without wasting data storage space. WHAT IS A TAG-FIELD? ______________________________________________________________ In the record definition we have the usual record header followed by three variables defined in the same manner as the records in the last two example programs. Then we come to the case statement. Following this statement, the record is different for each of the four types defined in the associated scalar definition. The variable WhatKind is called the tag-field and must be defined as a scalar type prior to the record definition. The tag-field selects the variant used, when the program uses one of the variables with this record type. The tag-field is followed by a colon and its type definition, then the reserved word OF. A list of the variants is then given, with each of the variants having the variables for its particular case defined. The list of variables for one variant is called the field list. A few rules are in order at this point. The variants do not have to have the same number of variables in each field list, and in fact, one or more of the variants may have no variables at all in its variant part. If a variant has no variables, it must still be defined with a blank followed by a semi-colon. All variables in the entire variant part must have unique names. The three variables, Wheels, Tires, and Tyres, all mean the same thing to the user, but they must be different for the compiler. You may use the same identifiers 11-5 Chapter 11 - Records again in other records and for simple variables anywhere else in the program. The Modula-2 compiler can tell which variable you mean by its context. Using the same variable name should be discouraged as bad programming practice because it may confuse you or another person trying to understand your program at a later date. USING THE VARIANT RECORD ______________________________________________________________ We properly define four variables with the record type Vehicle and go on to examine the program itself. We begin by defining one of our variables of type Vehicle, namely the variable named Ford. The seven lines assigning values to Ford are similar to the prior examples with the exception of the fourth line. In the fourth line the tag-field which selects the particular variant used is set equal to the value Truck, which is a scalar definition, not a variable. This means that the variables named Motor, Tires, and Payload are available for use with the record Ford, but the variables named Wheels, Engine, Tyres, etc. are not available in the record named Ford. Next, let's define the record Sunfish as a boat, and define all of its variables. All of sunfish's variables are defined but in a rather random order to illustrate that they need not be defined in a particular order. Recall the use of with from the last example program. To go even further in randomly assigning the variables to a record, we redefine Ford as having an Engine which it can only have if it is a car. This is one of the fine points of the record. If you assign any of the variant variables, the record is changed to that variant, but it is the programmers responsibility to assign the correct tag-field to the record, not the Modula-2 compiler's. Good programming practice would be to assign the tag-field before assigning any of the variant variables. The remainder of the Ford variables are assigned to complete that record, the non-variant part remaining from the last assignment. The variable named Mac is now assigned the value of the variable Sunfish. All variables within the record are copied to Mac including the tag-field, making Mac a boat. NOW TO SEE WHAT WE HAVE IN THE RECORDS ______________________________________________________________ We have assigned Ford to be a car, and two boats exist, namely Sunfish and Mac. Since Schwinn was never defined, it has no data in it, and is at this point useless. The Ford tag-field 11-6 Chapter 11 - Records has been defined as a car, so it should be true in the if statement in line 54, and the first message should print. The Sunfish is not a bicycle, so the statement in line 63 will not print. The Mac has been defined as a boat in the single assignment statement, so it will print a message with an indication that all of the data in the record was transferred to its variables. Even though we can make assignment statements with records, they cannot be used in any mathematical operations such as addition, or multiplication. They are simply used for data storage. It is true however, that the individual elements in a record can be used in any mathematical statements legal for their respective types. One other point should be mentioned. The tag-field can be completely eliminated resulting in a "free union" variant record. This is possible because Modula-2, as you may remember from above, will automatically assign the variant required when you assign data to one of the variables within a variant. This is the reason that all variables within any of the variants must have unique names. The free union record should be avoided in your early programming efforts because you cannot test a record to see what variant it has been assigned to. A NOTE TO PASCAL PROGRAMMERS ______________________________________________________________ A record with a free union variant is commonly used in Pascal to do type transfers, but this should be discouraged in Modula-2 since it has a complete set of carefully defined type transfer functions for that purpose. In addition, the method of data storage is not specified as a part of the language and a free union would not operate the same way with different compilers if used for the purpose of type transfer. PROGRAMMING EXERCISE ______________________________________________________________ 1. Write a simple program with a record to store the names of five of your friends and display the names. 11-7