======= LSN008.FormlPkg =======
!topic LSN on Generic Formal Packages
!reference MD-12.1.4;2.0
!from Tucker Taft 91-06-04
!discussion
> Could someone please provide a reasonable example or reason why one
> would want Packages as formal generic parameters? To date I have not
> come up with anything useful.
> ...stephen
That sounds like an excuse for an LSN...
Here is the "canonical" example of layered generics:
generic
type Float_Type is digits <>;
package Generic_Complex_Functions is
type Complex is record
Real, Imag : Float_Type;
end record;
function "+"(Left, Right : Complex) return Complex;
function "-"(Left, Right : Complex) return Complex;
function "*"(Left, Right : Complex) return Complex;
function "abs"(Right : Complex) return Float_Type;
. . .
end Generic_Complex_Functions;
. . .
package Long_Complex is new Generic_Complex_Functions(Long_Float);
Having already defined a generic package which implements complex
numbers, we now want to define a generic package which implements
complex matrices. Presume there is an existing instantiation
of the Generic_Complex_Functions package (e.g. Long_Complex),
and one wants to create an instantiation of the generic-complex-matrix
package which can interoperate with that preexisting instantiation.
Passing in the instantiation is the natural way to do this.
Hence:
generic
with package Complex_Pkg is new Generic_Complex_Functions(<>);
package Generic_Complex_Matrix_Operations is
type Complex_Matrix is array(Positive range <>, Positive range <>) of
Complex_Pkg.Complex;
function "*"(Left, Right : Complex_Matrix) return Complex_Matrix;
function "*"(Left : Complex_Pkg.Complex; Right : Complex_Matrix)
return Complex_Matrix;
. . .
end Generic_Complex_Matrix_Operations;
. . .
package My_Cmplx_Mtrx is
new Generic_Complex_Matrix_Operations(Long_Complex);
An alternative mechanism would have a generic formal private type
with each of the operations as additional formal parameters.
Anyone who has used Ada-83 generics heavily has seen that this
rapidly gets out of hand, with larger and larger generic formal
parts as the depth of the layering increases.
Passing in the instantiation captures the type and the operations
all in a single generic parameter.
In this case, it is intentional that the type be a visible
record type, and there is *no* way to pass in a visible record
type currently to a generic.
The Numerics Working Group has singled out the generic formal package
as particularly important to their work, because much of what
they write is formulated as generics.
----------------
Another application of the ability to pass in an instantiation
is when there are a group of types and/or operations which
together represent some useful abstraction like a (mathematical) "group"
or "ring" or "ideal" or ... One could define this abstraction
via a generic formal part on an empty package spec. E.g:
generic
type Group_Element is private;
Identity : constant Group_Element;
function Op(Left, Right: Group_Element) return Group_Element;
function Inverse(Right : Group_Element) return Group_Element;
package Group_Signature is end;
To proclaim that a type is a group over some operation
one "instantiates" this signature. E.g.:
package Integer_Addition_Group is
new Group_Signature(Integer,
Identity => 0,
Op => "+",
Inverse => "-"
);
Later, if one has another generic which is meaningful for any "group"
one can accept any instantiation of the Group_Signature generic. E.g.:
generic
with package Some_Group is new Group_Signature(<>);
package Derived_Group_Operations is
function Power(Left : Some_Group.Group_Element; Right : Integer)
return Some_Group.Group_Element;
-- Applies Op of group to left operand the number of times
-- specified by absolute value of right operand.
-- Returns Identity if Right is zero.
-- Returns Inverse of result if right operand is negative.
. . .
end Derived_Group_Operations;
=================
Note that the proposed "generic formal derived type" is an analogous
capability. The generic formal package allows one to define
additional operations and composite types (e.g. a matrix
type) for the class of types
corresponding to the types produced by the various
instantiations of a generic package.
The generic formal derived type allows one to define additional
operations and composite types for the class of types rooted at a given type.
My LSN on class-wide operations hopefully provides further
insight to this analogy.
-Tuck