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; |
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.