STRUCT, UNION & Conformity Clauses

Pitfall: a structure display needs at least two fields, so a one-field structure cannot be built with a display (assign the field instead).

30.1 Structures

Pitfall: a structure display needs at least two fields, so a one-field structure cannot be built with a display (assign the field instead).

BEGIN
   MODE POINT = STRUCT (REAL x, y);
   MODE PERSON = STRUCT (STRING name, INT age, POINT home);

   POINT p := (1.5, -2.0);                     # structure display #
   x OF p := 3.0;                              # field selection with OF #
   PERSON bob := ("Bob", 42, (0.0, 0.0));
   age OF bob +:= 1;
   print((name OF bob, " is ", whole(age OF bob, 0), newline));
   print(("home x = ", fixed(x OF home OF bob, 0, 1), newline))
END

30.2 Rows of structures and multiple selection

BEGIN
   MODE POINT = STRUCT (REAL x, y);
   [] POINT pts = ((0, 0), (3, 4), (6, 8));
   [] REAL xs = x OF pts;              # selecting from a row gives a row: (0, 3, 6) #
   print((xs, newline));
   print((y OF pts[2], newline))      # y of element 2 #
END

30.3 Unions

A UNION value carries both a value and the mode it currently holds:

You cannot use a union value directly in arithmetic; you must discriminate it with a conformity clause.

MODE NUMBER = UNION (INT, REAL);
NUMBER n := 42;          # uniting #
n := 3.14;               # now holds a REAL #

30.4 Conformity clauses

Each (MODE identifier): branch is taken if the union currently holds that mode; the identifier is bound to the value.

An OUT part handles unlisted modes; the brief form is ( v | (INT i): ... | ... ).

Conformity can test without binding: (MODE): with no identifier, e.g. CASE v IN (INT): print("int") OUT print("other") ESAC.

BEGIN
   MODE NUMBER = UNION (INT, REAL, STRING);
   PROC describe = (NUMBER v) VOID:
      CASE v IN
         (INT i):    print(("integer ", whole(i, 0), newline)),
         (REAL r):   print(("real ", fixed(r, 0, 3), newline)),
         (STRING s): print(("string """, s, """", newline))
      ESAC;
   describe(7);
   describe(2.5);
   describe("seven")
END

30.5 Example: shapes

CIRCLE (0, 0, 1) is a cast that makes the display a CIRCLE; the row display then unites each element into SHAPE. Note r OF c 2 means (r OF c) 2: selection binds tighter than any operator.

BEGIN
   MODE CIRCLE = STRUCT (REAL cx, cy, r);
   MODE RECT = STRUCT (REAL w, h);
   MODE SHAPE = UNION (CIRCLE, RECT);

   PROC area = (SHAPE s) REAL:
      CASE s IN
         (CIRCLE c): pi * r OF c ** 2,
         (RECT q):   w OF q * h OF q
      ESAC;

   [] SHAPE shapes = (CIRCLE (0, 0, 1), RECT (2, 3), CIRCLE (1, 1, 2));
   REAL total := 0;
   FOR i FROM LWB shapes TO UPB shapes DO total +:= area(shapes[i]) OD;
   print(("total area = ", fixed(total, 0, 4), newline))
END