modula-2 home

  Home  
  Tutorial  
  Win32 API  
  Reference  
  Projects  
 

 

Type declarations

Record types

Record types are structures that contain named components.  The named components can be of different types.  The components of a record are called fields.

Parts of a record can have multiple definitions to allow the information stored in a record to vary according to different needs.  These parts are called variant sections.

The identifier following CASE in variant sections is called the tag field of the variant section.  Its value indicates which variant is present in the record.

To specify record types, use:

RECORD
   FieldListSequence
END

FieldListSequence is:

FieldList {;FieldList}

FieldList is either of the following:

identifier {,identifier}: TypeSpecification

or

CASE [identifier] : TypeName OF
   variant {|variant}
[ELSE FieldListSequence]
END

Variant is:

[ CaseRange {,CaseRange}: FieldListSequence ]

CaseRange is:

expression [..expression] {, expression [..expression]}

Examples:

RECORD
   X, Y : REAL;
END

This record has two fields, X and Y, both of type REAL.  This record might be used to represent a point in a plane.

RECORD
   NEXT : NodePointer;
   CASE NT : NodeType OF
       Operator:
           op  : OperatorType;
           left, right : NodePointer;
       |
       Operand:
           value : REAL;
   END;
END

This record has one field, NEXT, followed by a variant section.  The variant section has two variants, one for the NodeType Operator and one for Operand.

A variant in a RECORD must handle all possible values of the tag field type. Thus if the CASE selector arms do not handle all possible values you must have an ELSE section in the CASE. The ELSE section can be empty. In this way you are informing the compiler you understand that all values are not handled and this is the necessary behavior.

Field selection

You can select a field of a record type variable as follows:

variable.field

Where variable is a record variable and field is the name of the field.

If the field is a part of a variant section with a tag field specified, it is an error to refer to any field in a variant other than the one specified by the tag field.

If you refer to a field in an incorrect variant, and the module was compiled with variant checking on, the program generates a runtime error.

Copying of variant records

The compiler allocates variables of variant record types the maximum amount of memory needed by any variant.  These variables are, therefore, capable of holding any variant, and copying one record to another will work correctly.

If you use the NEW standard procedure to allocate a variant record and specify the values of the tag fields, the compiler allocates only enough memory for the specific variants you selected.

You cannot do assignments of the entire record to records allocated in that way, because the amount of space allocated might not be large enough to hold the record you are assigning.

If you intend to do an assignment of the whole record, use NEW without specifying any tags.   In this case, the compiler allocates space for the largest variant.

Example:

   TYPE VARREC =
          RECORD
              CASE Tag : INTEGER OF
                 1: R : REAL; |
                 2: L : LONGREAL;
              ELSE
              END;
          END;
   VAR
      A : VARREC;
      B : POINTER TO VARREC;
   BEGIN
      NEW(B);
      B^ := A;  (* Correct *)
      NEW(B, 1);
      B^ := A;  (* Incorrect *)
   END;


Source:

  • Wirth N: Programming in Modula-2, 3rd ed. Springer Verlag, Berlin, 1985.
  • Stony Brook Modula-2 documentation. Used with permission. Note: Stony-Brook M2 offers an extended syntax with features not described here. Stony Brook M2 users are encouraged to visit the Stony Brook website and to consult the Stony Brook help system.