Record

Motivation | Related Components | Abstract Components | Concrete Components | Component Coupling Diagram

Record is a built-in type in RESOLVE/C++, which is included when you bring "RESOLVE_Foundation.h" into the global context. The name Record is therefore unusual: It is the name of a concrete template even though it does not end in "_2" or "_1a" or the like.


1. Motivation, Applicability, and Indications for Use


The programming type Record allows you to set up and access the individual objects in a small, fixed-size (no larger than ten) collection of objects of various and arbitrary types. You should consider Record whenever you want to treat such a collection of diverse objects as a single object for some purposes, and as individual constituent sub-objects for other purposes. The way you achieve the former behavior is straightforward, since this is what an "object" ordinarily is. The way you achieve the latter behavior simultaneously is to give symbolic names (called field names) to the sub-objects (also called fields) of a Record object. By using these field names with accessor operations, you can directly manipulate the fields of a Record  object. In fact, this is the only way to manipulate the sub-objects.

The mathematical model of a Record, then, is just a tuple whose members are the Record  fields. A convienent way to depict a Record object is to make a fixed-size table with two columns and as many rows as there are fields. In the left column of a row is a field name, which is the same for all objects of the same Record  type. The right column is the value of the sub-object with that field name, which is (generally) different among different objects of the same Record type.

Let's consider an example. Suppose you want to keep track of the following information for each employee of a company: first name, middle name, last name, address, and salary. For some purposes you want all the information about a particular employee to stay together (e.g., perhaps you want a Sequence whose Items are this Record type; or you want this Record type to be the R-Item in a Partial_Map, with the employee's ID number as the D_Item). For other purposes you want to be able to get to the individual pieces of informatio about a particular employee (e.g., perhaps you want to give the employee a raise).

There are several ways to use Record to do this. Here are two approaches:

  • You might instantiate the concrete_template class Record, calling the concrete_instance class Employee. In this instantiation you might declare five fields, of the types Text, Text, Text, Text, and Integer. Then you might declare Employee's field names to be first_name, middle_name, last_name, address, and salary, respectively. Schematically, you could view as follows an object of this type that contains information about John Q. Doe, and employee who lives at 123 Easy Street and makes $85,600 per year:

  •    "Employee" field name    field (sub-object) value
       first_name    "John"
       middle_name    "Q."
       last_name    "Doe"
       Address    "123 Easy St."
       Salary    85600

    The mathematical model of this value is a five-tuple:

         ("John", "Q.", "Doe", "123 Easy St.", 85600)
  • You might instantiate the concrete_template class Record, calling the concrete_instance class Full_Name. In this instantiation you might declare three fields of types Text, Text, and Text, and declare Full_Name’s field names to be first_name, middle_name, and last_name. Then you might instantiate the concrete_template class Record again, creating the concrete_instance class Employee with three fields of types Full_Name, Text, and Integer, and field names name, address, and salary. Schematically, you could view the situation like this:

  •    "Full_Name" field name    field (sub-object) value
       first_name    "John"
       middle_name    "Q."
       last_name    "Doe"

       "Employee" field name    field (sub-object) value
       name    ("John", "Q.", "Doe")
       Address    "123 Easy St."
       Salary    85600

    The mathematical model of this value is a three-tuple whose first component is another three-tuple:

         (("John", "Q.", "Doe"), "123 Easy St.", 85600)

    The first approach gives a “flat” Record with five fields and no further organization. The second approach — probably the better one from the standpoint of human understanding — gives a more “structured” Record, one of whose fields is itself a Record that is meaningful even outside the context of employee information. In fact, in practice you probably would need more detailed address information. So you’d also want to subdivide the address into street address, city, etc., by making a concrete_instance class Address as an instance of concrete_template class Record in much the same fashion as Full_Name above.

    On the other hand, suppose you also wanted to keep track of each employee’s birthdate. This suggests another concrete_instance class Date — which also would be generally useful outside this application. The mathematical model of Date probably should be a three-tuple of integers with some constraints on the values of the fields. However, Date should not simply be a Record instance because there also are mutual constraints on the values of the fields. That is, the day must be between 1 and 31 inclusive if the month is 1, but between 1 and 28 inclusive if the month is 2 (except if the year is a leap year, in which case 1 through 29 is allowed), and so on. The complication introduced by such a constraint is a clue that it is inappropriate to treat a date as merely three independent numbers which are placed together for convenience — which is how you’d be treating it if you made Date an instance of a Record implementation.

    You can guess from the above description that Record is a very unusual template component in the sense that different instantiations of it involve different numbers of template parameters! Indeed this is so, for here are the actual RESOLVE/C++ statements that declare the concrete_instance classes and their field names for the second approach above:

    
        concrete_instance
        class Full_Name :
            instantiates
                Record <
                       Text,
                       Text,
                       Text,
                       number_of_fields (3)
                    >
        {};
    
        field_name (Full_Name, 0, Text, first_name);
        field_name (Full_Name, 1, Text, middle_name);
        field_name (Full_Name, 2, Text, last_name);
    
        concrete_instance
        class Employee :
            instantiates
                Record <
                       Full_Name,
                       Text,
                       Integer,
                       number_of_fields (3)
                    >
        {};
    
        field_name (Employee, 0, Full_Name, name);
        field_name (Employee, 1, Text, address);
        field_name (Employee, 2, Integer, salary);

    A closely related component is Array. The most important difference is that the individual objects in a Record may be of different types; while all the individual objects in an Array — and in most other collections of objects — must be of the same type. However, a Record can contain at most ten fields, and the number of fields is fixed at instantiation time; while an Array may contain arbitrarily many objects and its size is determined at run-time by calling the Set_Bounds operation.

    One other component is closely related to Record. It is essentially identical to Record — except that its name is Representation — and it is used for one and only one thing in RESOLVE/C++ programs: If you are implementing a kernel abstraction, then you always collect together the individual objects that you are using to represent an object of the new type, and make them fields of an instance of Representation. Client programmers need to know nothing about Representation except that (a) it is essentially Record with a different name, and (b) it shouldn’t be used in ordinary client programs.

    2. Related Components


  • Array and Static_Array — types that are similar to Record except that they may contain objects of only one type; but they may contain far more objects than a Record
  • Representation — a type that is virtually identical to Record except that it is used in only one place: to hold the individual objects that comprise the representation of a kernel abstraction

  • 3. Component Family Members


    Abstract Components

  • Record_Type — the programming type of interest
  • Record_Accessor — one accessor for each field
  • Record — a bundle combining the components above; notice that it is not called Record_Kernel, the special name emphasizing that this is a special component which is instantiated and used in atypical fashion
  • Concrete Components

  • Record — This is the standard implementation of the abstract template Record which comes built-in to RESOLVE/C++. It uses a technique called “lazy initialization” so the constructor is very fast and takes time independent of the number and types of the fields. You pay the cost of the constructors for the fields only upon the first use of some Record accessor. The destructor’s execution time is essentially the sum of the execution times of the destructors for the fields (if the constructors have actually have been invoked). All the Record accessors take constant time once field construction takes place.
  • To bring this component into the context you write:

      #include "RESOLVE_Foundation.h"


    4. Component Coupling Diagram