1.8

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 xx and yy in the case of a Cartesian value or they are rr and φ\varphi in the case of a polar value.

21The set of values denoted by this type Coordinate is the union of the two types

T1=(x,y ⁣:real)T2=(r ⁣:real; φ ⁣:real)\begin{aligned} T_1 &= (x, y\colon \mathit{real}) \\ T_2 &= (r\colon \mathit{real};\ \varphi\colon \mathit{real}) \end{aligned}

and its cardinality is the sum of the cardinalities of T1T_1 and T2T_2.

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 sis_i and sijs_{ij} are the selector names of the components with constituent types TiT_i and TijT_{ij}, and sns_n is the name of the discriminating tag field with type TnT_n. The constants c1…cmc_1 \ldots c_m denote the values of the (scalar) type TnT_n. A variable xx of type TT consists of the components

x.s1,x.s2,…,x.sn,x.sk,1,…,x.sk,nkx.s_1, x.s_2, \ldots, x.s_n, x.s_{k,1}, \ldots, x.s_{k,n_k}

22if and only if the (current) value of x.sn=ckx.s_n = c_k. The components x.s1,…,x.snx.s_1, \ldots, x.s_n constitute the common part of the mm variants.

Consequently, using a component selector x.sk,h (1≤h≤nk)x.s_{k,h}\ (1 \le h \le n_k) when x.sn≠ckx.s_n \ne c_k 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)

SkS_k stands for the statement catering for the case that xx assumes the form of variant kk, i.e., it is selected for execution if and only if the tag field x.snx.s_n has the value ckc_k. As a consequence, it is fairly easy to safeguard against the misuse of selector names by verifying that each SkS_k contains only selectors

x.s1…x.sn−1x.s_1 \ldots x.s_{n-1}

and

x.sk,1…x.sk,nkx.s_{k,1} \ldots x.s_{k,n_k}

The purpose of the following short piece of program is to compute the distance between two points AA and BB given by the variables aa and bb 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).

Fig. 1.4 Cartesian and polar coordinates.
Fig. 1.4 Cartesian and polar coordinates.
23
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
↑ Up