Version 1.1 of ais/ai-30359.txt

Unformatted version of ais/ai-30359.txt version 1.1
Other versions for file 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); -- Freezing trouble here! type Seq_Of_Expr is access Expr_Sequences.Sequence;
function Operands(Expr : Expr_Ref) return Seq_Of_Expr;
...
private type Expression; -- completion deferred to body 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 => <>); -- partial instantiation
private
type A is record X : Inst.B; end record;
package Inst is new G(A, X, 3); -- completion of partial instantiation
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