Variants of Record Structures
In practice, it is often convenient and natural to consider two types simply as variants of the same type. For example, the type Coordinate of the preceding section may be regarded as the union of its two variants of Cartesian and polar coordinates whose constituents are (a) two lengths and (b) a length and an angle, respectively. In order to identify the variant actually assumed by a variable, a third component will be introduced. It is called the type discriminator or tag field.
type Coordinate = record case kind: (Cartesian, polar) of Cartesian: (x, y: real); polar: (r: real; φ: real) end
Here, the name of the tag field is kind, and the names of the coordinates are either and in the case of a Cartesian value or they are and in the case of a polar value.
21The set of values denoted by this type Coordinate is the union of the two types
and its cardinality is the sum of the cardinalities of and .
Very often, however, there are not two entirely distinct types to be united, but rather two types with partly identical components. It is this predominant situation which gave rise to the term variant record structure. An example is that of the type Person, defined in the preceding section in which the relevant characteristics to be recorded in a file depend on the sex of the person. For example, for a male, his weight and whether or not he is bearded may be regarded as relevant in a particular situation, but for a female, three characteristic measurements may be taken as significant (whereas her weight may be confidential). Following is a type definition resulting from such considerations:
type Person = record name, firstname: alfa; birthdate: Date; marstatus: (single, married, widowed, divorced); case sex: (male, female) of male: (weight: real; bearded: Boolean); female: (size: array[1 .. 3] of integer) end
The general form of a variant record type definition is
type T = record s₁ : T₁; ... ; sₙ₋₁ : Tₙ₋₁; case sₙ : Tₙ of c₁: (s₁,₁ : T₁,₁; ... ; s₁,ₙ₁ : T₁,ₙ₁); . . . . . . . . . . . . cₘ: (sₘ,₁ : Tₘ,₁; ... ; sₘ,ₙₘ : Tₘ,ₙₘ) end(1.24)
The and are the selector names of the components with constituent types and , and is the name of the discriminating tag field with type . The constants denote the values of the (scalar) type . A variable of type consists of the components
22if and only if the (current) value of . The components constitute the common part of the variants.
Consequently, using a component selector when must be regarded as a serious programming mistake and (in reference to the type Person defined above) amounts to asking whether or not a lady is bearded or (in the case of selective updating) ordering her to be so!
In using variant records utmost care is therefore required, and corresponding operations on the individual variants are best grouped in a selective statement, the so-called case statement, whose structure mirrors that of the variant record type definition.
case x.sₙ of c₁: S₁; c₂: S₂; ... cₘ: Sₘ end(1.25)
stands for the statement catering for the case that assumes the form of variant , i.e., it is selected for execution if and only if the tag field has the value . As a consequence, it is fairly easy to safeguard against the misuse of selector names by verifying that each contains only selectors
and
The purpose of the following short piece of program is to compute the distance between two points and given by the variables and of the variant record type Coordinate. The computational procedure differs according to the four possible combinations of Cartesian and polar coordinates (see Fig. 1.4).

case a.kind of Cartesian: case b.kind of Cartesian: d := sqrt(sqr(a.x-b.x)+sqr(a.y-b.y)); Polar: d := sqrt(sqr(a.x-b.r*cos(b.φ) +sqr(a.y-b.r*sin(b.φ)) end; Polar: case b.kind of Cartesian: d := sqrt(sqr(a.r*sin(a.φ)-b.x) +sqr(a.r*cos(a.φ)-b.y)); Polar: d := sqrt(sqr(a.r)+sqr(b.r) -2*a.r*b.r*cos(a.φ-b.φ)) end end