Version 1.1 of ais/ai-30359.txt
!standard 12.03 (02) 04-09-19 AI95-00359-04/01
!standard 12.03.01 (01)
!standard 13.14 (05)
!class amendment 04-09-19
!status work item 04-09-19
!status received 04-09-19
!priority Medium
!difficulty Hard
!subject Abstract generic instantations
!summary
To better support generic signature packages, and mutually dependent types that
involve generic instantiations, syntax is defined to allow a generic
instantiation can be split into two parts.
For such an instantiation, no freezing or elaboration occurs at the
point of the instantiation, rather it is deferred until a completion point.
Between the instantiation and the completion, only a partial view of the
instance is available.
!problem
Ada 95 provides formal package parameters. One way of using these parameters is
to define a "signature" for a class of abstractions, such as all set
abstractions, or all physical unit abstractions, and then build a new generic
abstraction on top of the original class of abstractions using this signature as
the template for a formal package parameter.
Unfortunately, it is difficult to use signatures because of the fact that an
instantiation freezes all of its actual parameters.
For example:
Given the signature for a set abstraction:
generic
type Element is private;
type Set is private;
with function Size(Of_Set : Set) return Natural is <>;
with function Union(Left, Right : Set) return Set is <>;
with function Intersection(Left, Right : Set) return Set is <>;
with function Empty return Set is <>;
with function Unit_Set(With_Item : Element) return Set is <>;
with function Nth_Element(Of_Set : Set) return Element is <>;
package Set_Signature is end;
... we could define a generic that required some set
abstraction, but it didn't care which one so long
as it implemented the above signature:
generic
with package Base_Set is new Set_Signature(<>);
package Layered_Abstraction is
type Cool_Type(Set : access Base_Set.Set) is limited_private;
procedure Massage(CT : in out Cool_Type; New_Set : Base_Set.Set);
...
end Layered_Abstraction;
Now if we want to define a set type and provide the pre-instantiated
signature for it, we run into trouble:
generic
type Elem is private;
with function Hash(El : Elem) return Integer;
package Hashed_Sets is
type Set is private;
function Union(Left, Right : Set) return Set;
...
package Signature is new Set_Signature(Elem, Set);
private
type Set is record
...
end record;
end Hashed_Sets;
The problem is that we can't do the instantiation of Set_Signature where we
would want to do so, because the instantiation freezes the type "Set"
prematurely.
A similar problem occurs when a type wants to include a pointer to a container
based on the type being defined. For example:
package Expressions is
type Expr_Ref is private;
package Expr_Sequences is new Sequences(Expr_Ref);
--
type Seq_Of_Expr is access Expr_Sequences.Sequence;
function Operands(Expr : Expr_Ref) return Seq_Of_Expr;
...
private
type Expression; --
type Expr_Ref is access Expression;
end Expressions;
Here we have a case where we want to instantiate a generic using a private type,
and use the results of the instantiation as the designated type of an access
type, which is in turn used as a parameter or result type of an operation on the
private type.
Unfortunately, we can't instantiate the "Sequences" generic with Expr_Ref, since
it is private.
!proposal
(See summary.)
!wording
Add to 12.3(2):
generic_instantiation ::=
...
| partial_package_instatiation
New section:
12.3.1 Partial Package Instantiation
A partial package instantiation can be used to declare a partial view of
a package instance. A corresponding full package instantiation provides
the full view of the instance. In contrast to a full instantiation,
the actual parameters to a partial package instantiation
may be private types or extensions prior to their full definition, allowing
mutual dependence between a type defined within an instance and the full definition
of its actual parameter types.
Syntax
partial_package_instantiation ::=
with package defining_identifier is
new generic_package_name partial_instantiation_actual_part;
partial_instantiation_actual_part ::=
(<>)
| [generic_actual_part]
| ([generic_association {, generic_association},] others => <>)
Any positional generic_associations shall precede any named
generic_associations.
Legality Rules
A partial_package_instantiation declares a partial instance;
such a declaration is allowed only as a declarative_item of the visible
part of a package, and it requires a completion. The completion of a
partial_package_instantiation shall be a (full) package instantiation, and
shall appear within the private part of the enclosing package.
The generic_package_name shall denote a generic package (the template
for the partial instantiation). The completion shall declare an instance
of the same template; the partial instance provides a partial view of this
instance. If the partial_instantiation_actual_part is (<>) or (OTHERS => <>),
there are no additional requirements on the completion; otherwise,
certain of the actual parameters of the completion shall match the corresponding actual
parameter of the partial instantiation, determined as follows:
* If the partial_instantiation_actual_part includes generic_associations
as well as "OTHERS => <>", then only the actual parameters specified
explicitly in these generic_associations are required to match;
* Otherwise, all actual parameters shall match, whether the actual
parameter is given explicitly or by default.
The rules for matching of actual parameters between the completion
and the partial instantiation are as follows:
* For a formal object of mode IN the actuals match if they are
static expressions with the same value, of if they statically
denote the same constant, or if they are both the literal NULL.
* For a formal subtype, the actuals match if they denote statically
matching subtypes.
* For other kinds of formals, the actuals match if they statically
identify the same entity.
For the purposes of matching, any actual parameter that is the name of
a formal object of mode IN is replaced by the formal object's actual
expression (recursively).
AARM NOTE: We considered using full conformance rules here instead of
formal-package-ish matching. However, conformance rules are only
appropriate for names or expressions which are not evaluated. However
formal objects or subprograms require that the actual names and expressions be
evaluated, which argues for static matching rather than conformance.
Static Semantics
The visible part of the partial view includes the first list of
basic_declarative_items of the package_specification. In addition,
for each actual parameter that is not required to match, a copy of the
declaration of the corresponding formal parameter of the template is
included in the visible part of the partial view. If the copied
declaration is for a formal type, copies of the implicit declarations
of the primitive subprograms of the formal type are also included in
the visible part of the partial view.
Dynamic Semantics
Elaborating a partial_package_instantiation evaluates the actual parameters.
Replace 12.7(2-10):
Syntax
formal_package_declaration ::=
with package defining_identifier is
new generic_package_name partial_instantiation_actual_part;
Legality Rules
The generic_package_name shall denote a generic package (the template for
the formal package); the formal package is an instance of the template.
The actual shall be an instance of the template. Certain of
the actual parameters of the actual shall match the corresponding actual
parameter of the formal package. The matching required corresponds
to that required between the actual parameters of a completion of a
partial_package_instantiation and those of the partial instance (see 12.3.1).
Static Semantics
A formal_package_declaration declares a generic formal package.
The visible part of a formal package includes the first list of basic_declarative_items
of the package_specification. In addition, if one or more actual parameters are
not required to match, copies of declarations from the formal part of the template
are also included in the visible part of the formal package, as for a partial instance
(see 12.3.1).
!discussion
It is a frustrating limitation to the use of generics, particularly as containers
and signatures, that they cannot be instantiated using a private type prior
to its completion. It is relatively common where a type directly or indirectly
contains a subcomponent that gives access back to an object of the enclosing type.
When using generics to provide abstraction, access types are often buried
within the abstraction rather than making them a visible part of the
abstraction. When taking this approach to implement, for example, a
set of objects, it is then perfectly reasonable for a type T to include as
a component a type representing a "set" of type T. However, the current
restrictions on generics make this impossible.
The other important use of an instantiation where the actual is a private
type is for "signature" generics. Such generics allow an abstraction to
be "bundled" up as an instance of a single generic, and then used as the
actual package for a formal package parameter in a subsequent instantiation.
Unfortunately, if the signature instantiation cannot itself be part of
the visible part of the original generic defining the abstraction, then
it becomes much less convenient, and ultimately much less useful. The instantiator
of the generic needs to separately instantiate the signature, so that
the writer of the generic has no clear way to specify that the generic
is declaring an abstraction that is consistent with the signature.
For example, if one establishes a "Map" signature, it would be natural
for the Hashed_Map generic and the Ordered_Map generic to both include
instantiations of the Map signature within their visible part. However,
the rule disallowing instantiations using private types prior to
their completion, makes this impossible.
Both of the above problems are solved by this partial instantiation
proposal.
During the Ada 9X process, we observed that there is a relationship between
generic formal parameter declarations and the kinds of partial views that you
would like to declare in the visible part of a package. In the generic,
the actual parameter "completes" the formal, whereas in the package, the
full definition in the private part "completes" the partial definition given
in the visible part. This proposal is essentially taking what is provided
by formal package parameters in a generic, and making an analogous capability
available in the visible part of a package.
!example
package P is
type A is private;
with package Inst is new G(A, others => <>); --
private
type A is record
X : Inst.B;
end record;
package Inst is new G(A, X, 3); --
end P;
The partial instantiation is like a formal package. It declares an instance
by optionally specifying some or all of the actual parameters. The instance
and its constituents are not "completely defined" until the full instantiation
is provided. Where the full instantiation is not visible, rules
analogous to those for formal packages apply in terms of referring to unspecified
actual parameters using the instance name as a prefix.
--!corrigendum 13.14(05)
!ACATS test
An ACATS test should be created for this feature.
!summary
!appendix
****************************************************************
Questions? Ask the ACAA Technical Agent