[Ada Information Clearinghouse]
Ada '83 Rationale, Sec 7.2: Informal Introduction to Derived Types

"Rationale for the Design of the
Ada® Programming Language"

[Ada '83 Rationale, HTML Version]

Copyright ©1986 owned by the United States Government. All rights reserved.
Direct inquiries to the Ada Information Clearinghouse at adainfo@sw-eng.falls-church.va.us.

CHAPTER 7: Derived Types

7.2 Informal Introduction to Derived Types

Given some useful type, the derivation mechanism offers a simple way of creating other types that are distinct copies of this type. Consider for example the types:

type SCALAR is digits 8;

type COLOR is (VIOLET, INDIGO, BLUE, GREEN, YELLOW, ORANGE, RED);

package METRIC is
  type COORDINATE is
    record
      X  :  SCALAR  :=  0;
      Y  :  SCALAR  :=  0;
      Z  :  SCALAR  :=  0;
    end record;

  function "+" (LEFT, RIGHT :  COORDINATE) return COORDINATE;
  function "-" (LEFT, RIGHT :  COORDINATE) return COORDINATE;

  procedure INVERT(A :  in out COORDINATE);
end METRIC;

By derivation we can create the following new types:

type MASS   is new SCALAR;
type LENGTH is new SCALAR;
type AREA   is new SCALAR;


type DYE is new COLOR;

type HUE is new COLOR;

type POINT is new METRIC.COORDINATE;
type FORCE is new METRIC.COORDINATE;
type VECTOR is new METRIC.COORDINATE;

The motivation for creating new types that are copies of existing types will be examined in later sections. For the time being let us review the properties of such types - obtained by derivation. In each case, the derived type is a copy of its parent type. This has several implications concerning the type class, the set of values, the applicable operations, and overloading.

Type Class:

The derived type belongs to the same class as its parent type. Thus DYE is an enumeration type since COLOR is an enumeration type; similarly, POINT is a record type since COORDINATE is a record type.

Set of Values:

The set of values of the derived type is a copy of the set of values of its parent type. Thus we have a set of seven values for the type DYE - exactly as for the parent type COLOR. There is a one-to-one correspondence between the two sets of values; but these two sets are nevertheless distinct: it would not be possible to assign a value of type DYE to a variable of type COLOR.

Basic Operations:

The basic operations for the derived type are as for the parent type. For example, if component selection is available for the parent type, it is available for the derived type. Thus selection of the component Y (by dot notation) is available for the type POINT since it is available for the type COORDINATE; similarly aggregates exist for both types and they use the same notation.

Attributes:

Attributes are basic operations, so the previous rule applies: If an attribute is available for the parent type, it is available for the derived type. Thus the attribute FIRST is available for the type MASS since it is available for the type SCALAR: the attribute FIRST for the type MASS yields a value of type MASS; the attribute FIRST for the type SCALAR yields a value of type SCALAR. The (implicit) declarations of these two attributes are in fact as follows (this is NOT legal Ada):

function SCALAR'FIRST           return SCALAR; -- for the type
SCALAR
function MASS'FIRST             return MASS;   -- for the type MASS

Implicit Conversions of Numeric Literals:

Implicit conversions of numeric literals are also basic operations. Hence there exists an implicit conversion of any real literal (such as 1.54) to the type MASS since there exists such a conversion for the type SCALAR (the parent type of MASS).

Enumeration Literals:

If a given enumeration literal exists for the parent type, there is a corresponding enumeration literal - with the same identifier - for the derived type. Thus there is the enumeration literal INDIGO for the type DYE since there is an enumeration literal INDIGO for the type COLOR. The (implicit) declarations of these two enumeration literals are in fact as follows:

function INDIGO return COLOR;   -- for the type COLOR
function INDIGO return DYE; -- for the type DYE

Thus each literal yields a value of the corresponding type: as we know already there is a correspondence between the indigo value of COLOR and that of DYE, but they are distinct values belonging to distinct types.

Predefined Operations:

For each predefined operation of the parent type there is a corresponding predefined operation of the derived type. For example we have the addition:

    function "+" (LEFT, RIGHT :  SCALAR) return SCALAR;

for the type SCALAR and hence the corresponding additions for the derived types:

function "+" (LEFT, RIGHT :  MASS)        return MASS;   -- for the type MASS
function "+" (LEFT, RIGHT :  LENGTH)      return LENGTH; -- for the type LENGTH
function "+" (LEFT, RIGHT :  AREA)        return AREA;   -- for the type AREA

Derivable Operations:

For a type declared in the visible part of a package, each subprogram that has a parameter or result of the type and is declared within the visible part of this package is derivable. This means that corresponding operations are derived by the derived type. For example, the package METRIC defines an addition, a subtraction, and a procedure INVERT for the type COORDINATE; and hence the corresponding subprograms are derived for the type POINT:

function "+" (LEFT, RIGHT :  POINT) return POINT;
function "-" (LEFT, RIGHT :  POINT) return POINT;
procedure INVERT(A :  in out POINT);

Note that these derived operations are obtained by systematic substitution of the name of the derived type for the name of the parent type.

(We will say more about the effect of these derived subprograms after we have presented explicit conversions.)

Explicit Conversions:

The above description shows that a derived type is very much like its parent type. They are nevertheless distinct types. Thus with the declarations

C  :  COLOR :=  INDIGO;
D  :  DYE  :=  VIOLET;
H  :  HUE  :=  RED;

assignments such as the following are illegal

D  :=  H;     -- Illegal: a hue value cannot be assigned to a dye
C  :=  D;     -- Illegal: a dye value cannot be assigned to a color

These assignments are not allowed because we are dealing with distinct types and distinct sets of values. However, there is a one-to-one correspondence between these sets of values and, for this reason, the language provides explicit conversions between corresponding values. For example

    DYE(H)

is an explicit conversion of the value of H - of type HUE - into the corresponding value of type DYE: here it will yield the RED value of the type DYE, and so the following assignment is legal

    D :=  DYE(H);

Type conversions between types that are derived directly or indirectly from each other (or from a common parent type) usually do not result in any run-time executable code. Such conversions are also involved (implicitly) in the derivation of a derivable operation. Consider for example the procedure INVERT:

procedure INVERT(A :  in out COORDINATE) is
begin
  A.X :=    - A.X;
  A.Y :=    - A.Y;
  A.Z :=    - A.Z;
end;

and the derivation of the procedure

    procedure INVERT(A :  in out POINT);

The effect of this derived operation is obtained by application of the parent procedure, but conversion of the parameter to the parent type is assumed to take place before the call, and conversion back to the derived type is assumed to take place after the call. Thus for a variable P of type POINT, the call

    INVERT(P);

has the same effect as

declare
  use METRIC;
  K :  COORDINATE;
begin
  K :=  COORDINATE(P);  -- convert to parent type
  METRIC.INVERT(K);     -- call parent procedure
  P :=  POINT(K);       -- convert back to derived type
end;

or simply

    METRIC.INVERT(METRIC.COORDINATE(K));

but this form does not show the conversion back.

Here again these conversions usually do not result in any run-time executable code but they are needed to explain the use of the procedure METRIC.INVERT, which is only applicable to the type METRIC.COORDINATE.

Overloading considerations:

A final point to consider with derived types is overloading. Derivation creates several overloaded entities. Thus we have

As usual, overloaded entities are identified by the context. Thus there is no ambiguity in the following cases:

C  :=  INDIGO;           -- the INDIGO of the type COLOR
D  :=  INDIGO;           -- the INDIGO of the type DYE

Qualification can be used when the context is not sufficient for the determination of the meaning of an overloaded construct. For example the following comparison is ambiguous (and admittedly somewhat pathological):

    if (X => A,  Y => B,  Z => C)  =  (X => U,  Y => V,  Z => W) then -- ambiguous

But this ambiguity can be resolved by qualification of one or of both aggregates:

    POINT'(X => A,  Y => B,  Z => C)     =  (X => U,  Y => V,  Z => W)

or

   POINT'(X => A,  Y => B,  Z => C)     =   POINT'(X => U,  Y => V,  Z   => W)

or

    (X => A,  Y => B,  Z => C)     =   POINT'(X => U,  Y => V,  Z   => W)

We next review major classes of use of derived types.


NEXTPREVIOUSUPTOCINDEX
Address any questions or comments to adainfo@sw-eng.falls-church.va.us.