[Ada Information Clearinghouse]
Ada '83 Rationale, Sec 7.6: The Construction of Private 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.6 The Construction of Private Types

For the construction of private types, derived types provide an easy and unambiguous way of distinguishing the operations of the private type from those of the type used for its representation (that is, the type declared by the full type declaration). The relevant aspects are: (1) the fact that the parent and the derived type are distinct types; (2) the fact that explicit conversions between the two types exist.

Consider for example the case where an operation specified for a private type is implemented in terms of an operation of the type that is used for representing the private type:

package LOCKSMITH is
  type KEY is private;
  procedure GET_KEY(K :  out KEY);
  ...
  function "<" (X, Y :  KEY) return BOOLEAN;
private
  type KEY is new CHARACTER;
  ...
end;

The user need not know that keys are implemented as characters, but he is provided with the operator "<" to order keys. This operator is implemented as the comparison of the corresponding characters:

package body LOCKSMITH is
  ...
  function "<" (X, Y :  KEY) return BOOLEAN is
  begin
    return CHARACTER(X) < CHARACTER(Y);
  end;
  ...
end LOCKSMITH;

The function first converts the parameters X and Y into characters and then compares them using character comparison. (Note that X < Y would not work: it would be a recursive call.)

A more general example of this problem is provided by the following schema

package P is
  type T is private;
  function F(X :  T) return T;
private
  type T is new REP;
  
there exists a function F operating on REP end P;

In order to implement the function F on T by means of that on REP we first convert the parameter to the type REP; then convert the result back to type T.

package body P is
  ...
  function F(X :  T) return T is
  begin
    return T(F(REP(X)));
  end;
  ...
end;

Without derivation, a solution can be developed using one-component records:

package P is
  type T is private;
  function F(X :  T) return T;
private
  type T is
    record
      VALUE :  REP;
    end record;
end;

package body P is
  ...
  function F(X :  T) return T is
  begin
    return T'(VALUE =>  F(X.VALUE));
  end;
  ...
end;

The function F is applied to the single component of the parameter; then a one-component aggregate is returned as the function result. The drawback of this solution is its lack of symmetry. Thus, compare

    return T(F(REP(X)));

with

    return T'(VALUE =>  F(X.VALUE));

Instead of the succession of two conversions - to REP and then back to T - we have now the succession of component selection (X.VALUE) and of aggregate construction T'(VALUE => ... ). Note that there are already cases where the language requires one-component records (for implicit initializations). For the remaining cases, however, the solution with derived types is more elegant.


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