Version 1.3 of ai05s/ai05-0074-4.txt

Unformatted version of ai05s/ai05-0074-4.txt version 1.3
Other versions for file ai05s/ai05-0074-4.txt

!standard 3.9.3 (9)          09-02-16 AI05-0074-4/02
!standard 3.10.1 (10/2)
!standard 7.3 (4)
!standard 7.3.1 (12/2)
!standard 7.3.1 (13)
!standard 10.2.1 (17/2)
!standard 12.3 (12)
!standard 12.3.1(0)
!class amendment 09-02-15
!status No Action (9-0-0) 10-02-27
!status work item 09-02-15
!status received 09-02-15
!priority Medium
!difficulty Hard
!subject Private Instantiations
!summary
(See proposal.)
!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:
with Sequences; 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
Introduce new syntax (a private_instantiation_declaration) that exports a view of a generic instance declared in the private part of a package specification so that a type with a partial view in the visible part of the package can be used as an actual in the instantiation.
The real generic_instantiation that completes a private_instantiation_declaration is explicitly placed after the full_type_declaration that completes the type with the partial view, so there are no freezing concerns with the generic instance, nor is there a need to change rules or add restrictions to the generic contract model.
Two types of views of an instance are defined. (A partial view of an instance, and a full view of an instance.) A partial view of an instance is associated with a private_instantiation_declaration. A full view of an instance is equivalent to the view of the instance provided by the generic_instantiation that completes the partial view at the site of the completion. A partial view of the instance applied to the immediately enclosing declarative region, while the full view is available to outside program units.
Semantically, it is as though a partial view of an instance sees a copy of the generic template, but the mapping from actuals to formals (and the corresponding substitutions) has not taken place yet, so the view has to make certain limiting assumptions about the types that are exported from the view.
For a partial view of an instance, it is assumed that every visible composite type declaration of the instance (other than array types) have been derived from a formal type that has a partial view (an assume the worst rule), thus each such exported type from the view is considered to have a partial view until the completion of the partial view of the instance.
A private type or private extenstion cannot directly contain a component of a composite type from the partial view of an instance, since such an exported type may have been derived from a formal which may be the private type or private extension. An array type would be allowed, but only if the components of the array are not composite types, as these situations otherwise could potentially create an illegal circular type. The full_type_declaration of a private type or private extension however may define a recursive data structure using access types to designate objects of a type from the partial view of the instance. If the view of the type is a tagged view, then private extension derivations are allowed before the completion of the partial view of the instance.
A partial view of an instance does not include any object declarations in the instance, which prevents any references to objects in the instance until the generic_instantiation that completes the partial view of the instance. The declaration of objects of types exported from the partial view is also not allowed until the completion of the partial view.
The syntax for a private_instantiation_declaration allows that actual parameters can be left unspecified until the private part of the package specification. This provides opportunities for improved data hiding and abstractions. Actuals for formal types and formal packagese cannot be deferred to the private part, but all other formals can. If the actual is visible at the place of a private_instantiation_declaration than it must be explictly named in the private_instantiation_declaration unless the formal has a default value or initialization.
!wording
Change 3.9.3 (9)
If a partial view {of a type} is not abstract, the corresponding full view shall not be abstract. If a generic formal type is abstract, then for each primitive subprogram of the formal that is not abstract, the corresponding primitive subprogram of the actual shall not be abstract.
Change 3.10.1 (10/2)
A prefix that denotes an object shall not be of an incomplete view {of a type}.
Change 7.3 (4)
A private_type_declaration or private_extension_declaration declares a partial view of the type; such a declaration is allowed only as a declarative_item of the visible part of a package, and it requires a completion, which shall be a full_type_declaration that occurs as a declarative_item of the private part of the package. The view of the type declared by the full_type_declaration is called the full view. A generic formal private type or a generic formal private extension is also a partial view {of a type. The view of a composite type of a partial view of an instance (see 12.3.1) that does not have an incomplete view and is not an array type, is a partial view of the type}.
AARM
4.a.1 All composite types (Record types, protected types, task types, etc) other than array types need to have the same restrictions as a private type or private extension if they are exported from a partial view of an instance, because we do not want to allow components of these types to be declared before the declaration of the full view of an instance that completes the partial view of the instance. Note that while an array type can be declared as a component of a type, it cannot be declared as a component of a private type or private extension if it has composite components because it is assumed that the components of the array have been derived from the private type or private extension.
Change 7.3.1 (12/2)
10 Partial views {of a type} provide initialization, membership tests, selected
components for the selection of discriminants and inherited components,
qualification, and explicit conversion. Nonlimited partial views also allow use of assignment_statements.
Change 7.3.1 (13) 11 For a subtype S of a partial view {of a type}, S'Size is defined (see 13.3). For an object A of a partial view {of a type}, the attributes A'Size and A'Address are defined (see 13.3). The Position, First_Bit, and Last_Bit attributes are also defined for discriminants and inherited components.
Change 10.2.1 (17/2)
A pragma Pure is used to declare that a library unit is pure. If a pragma Pure
applies to a library unit, then its compilation units shall be pure, and they shall depend semantically only on compilation units of other library units that are declared pure. Furthermore, the full view of any partial view {of a type} declared in the visible part of the library unit that has any available stream attributes shall support external streaming (see 13.13.2).
Change 12.3 (12)
A generic_instantiation declares {(a view of)} an instance; it is equivalent to the instance declaration (a package_declaration or subprogram_declaration) immediately followed by the instance body, both at the place of the instantiation.
Add new section: 12.3.1 Private Instantiations
Add 12.3.1(1 - 31):
1 The declaration (in the visible part of a package) of a private instantiation serves to allow a generic package to be instantiated with an actual that has a partial view of a type.
SYNTAX
2 private_instantiation_declaration ::=
package defining_program_unit_name is private new generic_package_name [deferred_generic_actual_part];
3 deferred_generic_actual_part ::=
(deferred_generic_association {, deferred_generic_association})
4 deferred_generic_association ::=
[generic_formal_parameter_selector_name =>] explicit_generic_actual_parameter | [generic_formal_parameter_selector_name =>] PRIVATE | OTHERS => PRIVATE
5 A deferred_generic_association is named or positional according to whether or not the generic_formal_parameter_selector_name is specified. Any positional associations shall precede any named associations. If there is an association with the rserved word OTHERS, it shall come last.
LEGALITY RULES
6 A private_instantiation_declaration declares both a Partial View and a Full View of an instance; such a declaration is allowed only as a declarative_item of the visible part of a package, and it requires a completion, which shall be a generic_instantiation of a package. The completion of a private_instantiation_declaration occurs as a declarative_item of the private part of the package.
7 The generic_formal_parameter_selector_name of a deferred_generic_association shall denote a generic_formal_parameter_declaration of the generic unit being instantiated if the deferred_generic_association has an explicit_generic_actual_parameter. If two or more formal subprograms have the same defining name, then named associations are not allowed for the corresponding actuals.
8 A private_instantiation_declaration shall contain at most one deferred_generic_association for each formal. Each formal without an association shall have a default_expression or subprogram_default.
9 The actual parameters of a private_instantiation_declaration shall match the corresponding actual parameters of the completion, whether the actual parameters are given explicitly or by default.
10 The rules for matching of actual parameters between the completion and the private instantiation are as follows:
11 * A named association with the reserved word OTHERS matches all needed
actual parameters from the completion that are not associated with some previous association.
12 * If an association is a named association in the private instantiation
then the association shall be a named association in the completion unless the actual parameters are given by default and the association has the reserved word OTHERS in the private instantiation. If an association is a positional association in the private instantiation then the association shall be positional in the completion.
13 * An association with the reserved word PRIVATE but without the reserved
word OTHERS matches the actual of the completion that has the same generic_formal_parameter_selector_name if the association is a named association, or the actual in the corresponding relative position within the generic_actual_part if the association is a positional association.
14 * 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.
15 * For a formal subtype, the actuals match if they denote statically
matching subtypes.
16 * For other kinds of formals, the actuals match if they statically
denote the same entity.
AARM NOTE: We considered using full conformance rules here instead of
formal-package-ish matching. However, we wanted to use rules consistent with formal packages, and it seemed simpler to just define the particular matching rules needed between instantiations. Also we wanted to ensure that no evaluations would take place at the point of the private instantiation.
17 If the actual of a generic_instantiation that completes a private_instantiation_declaration is visible at the place of the private_instantiation_declaration then there shall be a deferred_generic_association with an explicit_generic_actual_parameter that names the actual, if the associated formal does not have a default_expression or subprogram_default.
18 A private_instantiation_declaration shall not have a deferred_generic_association with an explicit_generic_actual_parameter that has an incomplete view at the place of the private_instantiation_declaration.
19 A private_instantiation_declaration shall have a deferred_generic_association with an explicit_generic_actual_parameter for every formal_type_declaration and formal_package_declaration of the completion.
20 Neither the declaration of a variable of a type from a partial view of an instance, nor the creation by an allocator of an object of a type from the view of the instance, are allowed before the completion of a private_instantiation_declaration. Similarly, before the completion, such a type cannot be used in a generic_instantiation or in a representation item.
21 All visible composite types other than an array type of a partial view of an instance that do not have an incomplete view have a partial view. If the view of the type is a tagged view, then the view of the type is a tagged partial view.
AARM
21.a Ramification: It is assumed that all such types have been derived from a formal type that has a partial view, or contains a component of a formal type that has a partial view (An assume the worst rule). By saying that these types have partial views, it prevents the declaration of illegal recursive types, or declaring other composite types with components that have a partial view of a type before the completion of the partial view of the instance in the private part. An derivative of an array type is allowed to be declared, but if the components of the array are composite types then the array is considered to be an array of types that have a partial view. This prevents the declaration of an array component within the completion of a private type or private extension which could lead to an illegal recursive type declaration.
22 The partial view of a type of an explicit_generic_actual_parameter of a deferred_generic_association must be conformant to the formal type declaration of the generic package specification. Specifically, if the partial view of a type is a limited view, then the formal_private_type_definition shall have the reserved word LIMITED in the formal type declaration. If the partial view of a type is an untagged view, then the formal_private_type_definition shall not have the reserved word TAGGED in the formal type declaration.
AARM
22.a This rule is needed because the full view of an untagged limited partial view may be of a type with an unlimited view. Similarly, a full view of an untagged partial view may be of a type that has a tagged view. We dont want to allow a generic_instantiation in the private part of a package that conflicts with the declarations of the actuals used in a private_instantiation_declaration.
STATIC SEMANTICS
23 A private_instantiation_declaration declares a private instantiation.
24 A private_instantiation_declaration defines two views of a generic instance. The declaration of a partial view of an instance defines the operations that are available within the immediately enclosing declarative region. The declaration of the full view defines the operations that are available to outside program units. The full view is equivalent to the view of the instance declared by the generic_instantiation that completes the private_instantiation_declaration.
25 A partial view of an instance is a view of a copy of the text of the generic template whereby the substitution of formal parameters with actual parameters has not taken place, and the mappings of actual parameters to formal parameters of the generic_instantiation are considered to be unresolved.
26 A partial view of an instance does not include a view of any object declarations from the instance.
AARM
26.a We do not want to allow any references to objects of a private view of an instance until the completion of the deferred_instantiation_declaration. This is because the objects really do not come into existence until the generic_instantiation declaration.
NOTES
27 The full_type_declaration that completes a partial view of a type cannot declare a component of a type from a partial view of an instance because it is assumed that any type of the instance could have been derived from the type with the partial view, and thus could potentially create an illegal circular data type.
28 A new type cannot be derived from a type from a partial view of an instance unless the type is a tagged type, since such a type may have been derived (directly or indirectly) from an actual that has a partial view. Such a derivation must be either a tagged private type or a tagged private extension.
!discussion
This proposal solves several problems that come up frequently in practice with private types. Certainly the most common is a desire to include an instantiation of a generic (possibly a signature generic as mentioned in the "problem" section above, or perhaps a container generic), with a private type as one of the actual parameters to the instantiation.
A second problem is a desire to be able to have a recursive data structure where a type declaration can contain a component that designates a type from an instance that was instantiated with an actual of the composite type.
An instantiation requires the type of an actual to be defined first, and since the instantiation comes after the type declaration, the type declaration cannot name any type declarations of the instantiation.
A third problem extends from the second problem as it is desirable that it be possible to declare such a recursive data structure that has a primitive that has a formal parameter of the type of a component that designates an object of an instantiated type or returns a result value of a component that designates an object of an instantiated type.
A fourth problem is another variant of the third, where it is desirable that it be possible to declare such a recursive data structure that has a primitive that has a formal parameter of the type of a component that is an instantiated type, or returns a result value of a component that is an instantiated type. In addition, we would like it to be possible to declare such a recursive type as a remote access to class wide type allowing usage in distributed applications.
A fifth problem is a desire to export a type derived from a tagged type that is exported from a generic instance that has a private type as one of the actual parameters.
A sixth problem is a desire to instantiate a generic in the visible part of a package, yet defer the declarations for some or all of the actuals to the private part of the package.
The basic idea of this proposal is to add syntax that provides more flexibility and capabilities for exporting functionality in the visible part of a package specification, creating recursive data structures, and hiding implementation details in the private part of a package specification.
This proposal is limited to packages because you can use renaming-as-body to get these effects for subprogram instantiations. Moreover, you cannot export a type from a generic subprogram, so there is no possibility of recursive use. [Note that we could lift this limitation if it if felt to be more regular.]
Ada 2005 provides solutions to some of these problems, but they are not ideal. For the first example, making the instantiation a child unit solves the problem. However, this is annoying, because accessing the instance requires an extra with and instantiation (since children of generics must be generic):
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; ... private type Set is record ... end record; end Hashed_Sets;
generic package.Hashed_Sets.Signature is package The_Signature is new Set_Signature(Elem, Set); end Hashed_Sets.Signature;
A user of Hashed_Sets must with and instantiate Hashed_Sets.Signature in order to access the instance.
A simpler alternative involves the use of nested packages. This is better, but introducing a nested package can still be considered to be awkward.
generic type Elem is private; with function Hash (El : Elem) return Integer; package Hashed_Sets is package Sets is type Set is private; function Union(Left, Right : Set) return Set; private type Set is record ... end record; end Sets;
use Sets; package The_Signature is new Set_Signature(Elem, Set);
end Hashed_Sets;
The second problem can also be solved in some cases with child units, using the limited with:
with Sequences; limited with Expressions.Sequences; package Expressions is type Expr_Ref is private; type Seq_Of_Expr is access Expressions.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;
package Expressions.Sequences is package Expr_Sequences is new Sequences(Expr_Ref); type Sequence is new Expr_Sequences.Sequence; end Expressions.Sequences;
Here, besides the extra with clause, we need to declare an extra type simply so that the type is visible to the limited with clause (which operates purely syntactally). This means that extra type conversions are necessary. Another limitation is that this technique requires a type derivation (Sequence), and would not work for types that cannot be extended, such as synchronized tagged types.
Once again, the use of nested packages provides a simpler work around, but this still requires the extra type and having to declare a nested package can still be viewed as being awkward. Such a technique is something that would likely require the awareness of an expert Ada programmer, as it is questionable whether a less experienced programmer would come up with this technique on their own.
with Sequences; package Expression_Sequences is
type Expr_Seq; -- incomplete type type Seq_Of_Expr is access Expr_Seq;
package Expressions is type Expr_Ref is private; function Operands(Expr : Expr_Ref) return Seq_Of_Expr; ... private type Expression; -- completion deferred to body type Expr_Ref is access Expression; end Expressions;
use Expressions;
package Expr_Sequences is new Sequences(Expr_Ref); type Expr_Seq is new Expr_Sequences.Sequence; --completion of incomplete type
end Expression_Sequences;
This proposal attempts to provide a more intuitive approach for solving these and other problems and eliminates limitations that currently exist in the language as well as introduce new capabilities for data hiding and better abstractions.
First of all, an important capability is to be able to instantiate a generic with a private type or private extension as an actual. The concept is to place the generic instantiation in the private part after the completion of the private type or private view, but provide a view of the instance in the visible part of the package that is exported to outside program units.
This new syntactic construct is called a private_instantiation_declaration. This is a declaration that is placed in the visible part of a package. It is completed by a generic_instantiation in the private part of the package. We now say that a generic_instantiation declares a full view of an instance. A private_instantiation_declaration also declares a full view of the instance, but that view is only available to outside program units. A private_instantiation_declaration also declares what is called a partial view of an instance which only applies to the immediately enclosing declarative region. A private_instantiation_declaration can be distinguished from a generic_instantiation by the use of the word PRIVATE in the syntax.
e.g.,
with Ada.Containers.Doubly_Linked_Lists; package Pkg is type T is private; package I is private new Ada.Containers.Doubly_Linked_Lists (T); private type T is null record; package I is new Ada.Containers.Doubly_Linked_Lists (T); end Pkg;
The intent is that the exported (full) view of the instance of I is effectively the same as the view if the generic had been instantiated from outside the enclosing package;
i.e.
with Ada.Containers.Doubly_Linked_Lists; package Pkg is
package Nested is type T is private; private type T is null record; end Nested;
use Nested; -- "use all Nested" would be better here package I is new Ada.Containers.Doubly_Linked_Lists (T); end Pkg;
Now suppose we would like type T to be a recursive structure having a component that designates a type provided by the partial view of the instance. In Ada 2005, it is currently possible to achieve this using an approach involving a nested package and an Incomplete Type declaration.
e.g.,
with Ada.Containers.Doubly_Linked_Lists; package Pkg is type List_Type;
package Nested is type T is private; private type T is record List : access List_Type; end record; end Nested;
use Nested; -- "use all Nested" would be better here package I is new Ada.Containers.Doubly_Linked_Lists (T); type List_Type is new I.List with null record; -- ERROR Cannot derive if I.List is a syncronized tagged type end Pkg;
Note that the programmer really just wants to instantiate a list of T in the visible part of the package. Here the programmer has had to jump through three mental hurdles to achieve this. The programmer has to think of declaring a nested package, declaring an incomplete type outside the nested package, and completing the an incomplete type with an derived type from an instance. It is quite likely that a reasonably experienced programmer would not come up with this solution on their own, and this would have to be filed away in a book of "tricks" to get around programming problems that one might run into.
This proposal provide an more intuitive syntax that more closely maps to what the programmer wanted to express. Compare the complexity of the visible part of the example above, with the two line visible part using the new proposed syntax below. One cannot help but have to mentally process the private part in the example above as well, whereas in the example below, the mind is much more at ease without having to peek at the private part. If Ada is supposed to be a language involving code that is written once but read many times, then the improved readability of the new syntax should continue to generate savings over the maintainance lifecycle of the software. e.g.
with Ada.Containers.Doubly_Linked_Lists; package Pkg is type T is private; package I is private new Ada.Containers.Doubly_Linked_Lists (T); private type T is record; List : access I.List; end record; package I is new Ada.Containers.Doubly_Linked_Lists (T); end Pkg;
Note also, that if we replace the use of Ada.Containers.Doubly_Linked_List with a different container such as a protected queue that inherits from a synchronous interface, then the Ada 2005 example above wont even compile whereas the new proposed syntax will compile. This is because it is currently not possible to derive a new type from a synchronized tagged type. The Ada 2005 version relies on a type derivation of the private type whereas the new proposed syntax does not involve any type derivations. One might argue that perhaps Ada 2005 should be modified to allow derivations of synchronized tagged types. That may be true and perhaps that capability will be added to the language at some point in the future, but still it is less than ideal that the programmer is being forced to derive a new type here, when it really has nothing to do with the abstraction.
Taking this example one step further. Suppose we now want to introduce a primitive subprogram that exports the value of a recursive component. In Ada 2005, the workaround example now becomes;
with Ada.Containers.Doubly_Linked_Lists; package Pkg is type List_Type; type List_Ref is access List_Type;
package Nested is type T is private; function Get_List (Item : T) return List_Ref; -- Cannot return anonymous access type here because function cannot -- be dispatching on more than one type private type T is record List : List_Ref; end record; end Nested;
use Nested; -- "use all Nested" would be better here package I is new Ada.Containers.Doubly_Linked_Lists (T); type List_Type is new I.List with null record; end Pkg;
Here we needed to introduce a named access type because otherwise the Get_List subprogram would generate a compile error because the Get_List function cannot be dispatching on more than one type.
With the new proposed syntax, there is little change other than the additional primitive, since the I.List has a partial view, it can be returned with an anonymous access type. With the proposed syntax, you have more of a choice whether to use named access types or not.
with Ada.Containers.Doubly_Linked_Lists; package Pkg is type T is private; package I is private new Ada.Containers.Doubly_Linked_Lists (T); function Get_List (Item : T) return access I.List; private type T is record; List : access I.List; end record; package I is new Ada.Containers.Doubly_Linked_Lists (T); end Pkg;
Now consider that we would like to make T a tagged type and we would like to export a primitive of the tagged private type that returns the value of an object of an instantiated type that is designated by a component.
In Ada 2005, we would modify the workaround example as follows;
e.g.,
with Ada.Containers.Doubly_Linked_Lists; package Pkg is type List_Type; type List_Ref is access List_Type;
package Nested is type T is tagged private; private type T is tagged record List : List_Ref; end record; end Nested;
use Nested; -- "use all Nested" would be better here package I is new Ada.Containers.Doubly_Linked_Lists (T); type List_Type is new I.List with null record; function Get_List (Item : T) return List_Type; end Pkg;
The Get_List function has to be declared after the instantiation outside the nested package where T is declared, since List_Type is an incomplete type from within the context of the Nested package and it is not possible to declare a function that returns a value of an incomplete type. The problem is that Get_List is not a primitive function of T. Any derivations of T do not include the Get_List primitive.
With the new proposal, this is not a problem because the type I.List has a partial view. (The partial view of an instance assumes that all exported types of the view may have been derived from a formal type and thus are considered to have a partial view) This means that Get_List can be declared as a primitive of T, and thus is inherited by any derived types of T.
with Ada.Containers.Doubly_Linked_Lists; package Pkg is type T is tagged private; package I is private new Ada.Containers.Doubly_Linked_Lists (T); function Get_List (Item : T) return I.List; private type T is tagged record; List : access I.List; end record; package I is new Ada.Containers.Doubly_Linked_Lists (T); end Pkg;
Now suppose we would like to use this example in a distributed application, as a Remote_Types package. We run into several problems and a fatal roadblock that prevents a compilable solution in Ada 2005.
The hopeless workaround code we get ends up looking like;
with Ada.Containers.Doubly_Linked_Lists; package Pkg is
pragma Remote_Types;
type List; -- Incomplete View type RACW_T; -- Incomplete_View of a RACW?
-- type List_Ref is access List; -- ERROR Could not use List_Ref declaration because of E.2.2 (9/3) and -- E.2.2 (9.2/3). So we try to go back to using an anonymous access type
package Nested is type L is limited interface; type T is synchronized new L with private; procedure Create (Item : in out T; Other : access RACW_T); -- Not a RACW here because anonymous access type of an incomplete view -- Cant do this because of E.2.2 (14/3)
package Doubly_Nested is
function Get_List (Item : T) return access List; -- Needs to be doubly nested because otherwise compiler -- complains saying that operation can be dispatching in -- only one type -- ERROR: Nevermind, this wouldn't be allowed anyway because of -- E.2.2 (14/3)
end Doubly_Nested; -- BAD BAD BAD having to return access to protected component!!!
private
protected type T is new L with procedure Create (Item : access RACW_T); function Get_List return access List; -- Cant return List without it being an access type here, -- since nested package only sees incomplete view. private The_List : access List; end T;
end Nested;
type RACW_T is access all Nested.T'Class; -- RACW_T becomes a RACW here
package I is new Ada.Containers.Doubly_Linked_Lists (RACW_T);
type List is new I.List with null record; function Get_List (Item : Nested.T) return List;
end Pkg;
With the proposed new syntax, we actually get a working solution, without having to pull out any hair.
with Ada.Containers.Doubly_Linked_Lists; package Pkg is
pragma Remote_Types;
type L is limited interface; type T is synchronized new L with private; type RACW_T is access all T'class; procedure Create (Item : in out T; Other : RACW_T); package I is private new Ada.Containers.Doubly_Linked_Lists (RACW_T); function Get_List (Item : T) return I.List;
private
protected type T is new L with procedure Create (Item : RACW_T); function Get_List return I.List; private List : access I.List; end T;
package I is new Ada.Containers.Doubly_Linked_Lists (RACW_T);
end Pkg;
It seems worth considering whether anyone would want to write a distributed application with this form. It is not hard to come up with an good example. Suppose we wanted to write a distributed social networking application similar to facebook. Consider a Remote Types package representing a person (type T in the example above). A person has a list of friends or contacts which are also persons (The List in the example above). We might want another person to be able to remotely retrieve the list of friends from the RACW value representing a different person (The Get_List function in the example above) so that the other person can consider whether any of the friends from the resulting list are also friends of the other person.
It turns out there are other problems with syncronous types, even if we give up on the idea of trying to make the workaround work in a distributed application. Suppose we just want to have type T be a protected type in a recursive structure that stores a list of references to type T, where we want to have a primitive that returns the list of references.
In Ada 2005, the workaround initially becomes;
with Ada.Containers.Vectors; package Pkg is
type List; -- Incomplete View
package Nested is type List_Ref is access List; type L is limited interface; type T is synchronized new L with private; type T_Ref is access all T; procedure Initialize (Item : in out T; Id : Natural); function "=" (L, R : T) return Boolean; procedure Append (Item : in out T; Other : T); function Get_List (Item : T) return List_Ref; -- BAD BAD BAD access to protected component!!!
private
protected type T is new L with procedure Initialize (Id : Natural); procedure Append (Item : T_Ref); function Id return Natural; function Get_List return List_Ref; -- Cant return List without it being an access type here, -- since nested package only sees incomplete view. -- This is BAD! Access to protected component! private Unique_Id : Natural; The_List : List_Ref; end T; end Nested;
package I is new Ada.Containers.Vectors (Index_Type => Natural, Element_Type => Nested.T_Ref, "=" => Nested."=");
type List is new I.Vector with null record; function Unsafe_Get_List (Item : Nested.T) return List; -- Looks safe but it really isnt because it has to get -- a pointer to a protected list, while it is copying the -- list in the return value, someone else could be -- modifying it.
end Pkg;
The problem here is that we are forced to return an access to a component of a protected object. This object (an access to Vector) is not safe to use because when Unsafe_Get_List is called, under the covers it has to call the Get_List protected function, and then return the dereferenced value. While Unsafe_Get_List is building the return object by dereferencing the return value, another task could be modifying the list via the Append call. This could lead to a nasty memory corruption problem. To get around this issue, one would have to replace the container being used in this example with a protected container. This also rules out containers that are synchronous tagged types because a type derivation is needed (type List), which is currently not possible with synchronous tagged types. Even if the programmer finds or creates a suitable container, this adds an extra protected structure which is less efficient.
With the new Syntax you can safely use any of the common Ada 2005 container libraries, and there is no need to introduce an extra protected object. This example shows;
a) Improved flexibility (More containers can be used safely, including
non-synchronous containers and containers of a synchronous tagged type)
b) Improved efficiency (List does not need to be synchronous) c) Improved data hiding ("=" for T can be hidden in private part)
(See next examples for explanation)
d) Improved readability (Compare visible parts,
7 contiguous lines vs 13 lines with a nested private part inbetween to distract the reader)
with Ada.Containers.Vectors; package Pkg is
type L is limited interface; type T is synchronized new L with private; type T_Ref is access all T; procedure Initialize (Item : in out T; Id : Natural); procedure Append (Item : in out T; Other : T);
package I is private new Ada.Containers.Vectors (Element_Type => T_Ref, Index_Type => Natural, others => private); -- Note "=" is deferred to private part
function Get_List (Item : T) return I.List;
private
protected type T is new L with procedure Initialize (Id : Natural); procedure Append (Item : T_Ref); function Id return Natural; function Get_List return I.List; private Unique_Id : Natural; List : access I.List; end T;
function "=" (L, R : T) return Boolean;
package I is new Ada.Containers.Vectors (Index_Type => Natural, Element_Type => T_Ref, "=");
end Pkg;
Now suppose we would like to be able to hide more details associated with a private_instantiation_declaration in the private part of a package specification. In particular, we want to be able to declare certain actuals in the private part, instead of having to declare them in the visible part of a package specification.
For example:
Supposing we have a generic package that can be used to create a specific abstraction, and we want the generic instantiation of this package to directly provide all the operations that are available to clients in the package containing the specific abstraction.
In other words, the generic instantiation needs to be declared in the visible part of the package associated with specific abstraction.
Currently this requires that all the generic actuals be fully visible at the point of the generic instantiation. This can lead to the exposure of constants, variable, subprograms, and entries in the visible part of the package that might have been better off hidden from view.
To illustrate these points, consider the following generic that provides a template for a device driver which can be plugged into some fictional target OS.
generic type Device_Type is private; Manufacturer : String; Model : String; Disabled : in out Boolean; with procedure Activate_Device (Device : Device_Type); with function Device_Is_Operational (Device : Device_Type) return Boolean; package Device_Driver is
protected Driver is procedure Activate; function Is_Operational return Boolean; private Device : Device_Type; end Driver; end Device_Driver;
package body Device_Driver is protected body Driver is
procedure Activate is begin Activate_Device (Device); end Activate;
function Is_Operational return Boolean is begin return Device_Is_Operational (Device); end Is_Operational; end Driver; end Device_Driver;
Now Suppose we want to create an Audio Driver that utilizes this generic. We really want to to expose just the calls provided by the generic to Activate the audio driver, and to check to see if the audio driver Is_Operational. Unfortunately, we end up having to expose other details that clients might have no business looking at, and the package specification suffers from poor readability due to the excess clutter.
with Device_Driver;
package Audio_Driver is
type Audio_Device is private;
procedure Power_On (Device : Audio_Device); -- Actual procedure function Playing_Music (Device : Audio_Device) return Boolean; -- Actual Function
Muted : Boolean := False; -- Actual Variable
Manfacturer : constant String := "Acme Corp"; Model : constant String := "SoundWhomper Mark IV";
package Audio_Device_Driver is private new Device_Driver (Device_Type => Audio_Device, Manufacturer => Manufacturer, Model => Model, Disabled => Muted, Activate_Device => Power_On, Device_Is_Operational => Playing_Music);
private
type Audio_Device is record ... end record;
package Audio_Device_Driver is new Device_Driver (Device_Type => Audio_Device, Manufacturer => Manufacturer, Model => Model, Disabled => Muted, Activate_Device => Power_On, Device_Is_Operational => Playing_Music);
end Audio_Driver;
The idea is to be able to indicate that declarations for actuals of the partial generic instantiation in the visible part of a package specification are being deferred into the private part of a package specification. The private keyword is used in the declaration of the private_instantiation_declaration to indicate that a particular actual (or group of actuals if the named association is others) is being deferred to the private part of the package specification.
Applying the syntax for a private_instantiation_declaration to the above allows us to write;
with Device_Driver;
package Audio_Driver is type Audio_Device is private;
package Audio_Device_Driver is private new Device_Driver (Device_Type => Audio_Device, others => private);
-- These renamed subprograms are the only visible operations procedure Activate renames Audio_Device_Driver.Driver.Activate; function Is_Operational return Boolean renames Audio_Device_Driver.Driver.Is_Operational;
private
type Audio_Device is record ... end record;
procedure Power_On (Device : Audio_Device); -- Actual procedure function Playing_Music (Device : Audio_Device) return Boolean; -- Clients cannot call these functions
Muted : Boolean := False; -- Actual Variable Manfacturer : constant String := "Acme Corp"; Model : constant String := "SoundWhomper Mark IV";
package Audio_Device_Driver is new Device_Driver (Device_Type => Audio_Device, Manufacturer => Manufacturer, Model => Model, Disabled => Muted, Activate_Device => Power_On, Device_Is_Operational => Playing_Music);
end Audio_Driver;
A second example of using deferred actuals would be helpful. Suppose we have a set of container packages that implement a queue abstraction. The root package defines the interface to a queue, and child packages create various implementations of the interface
generic type Element_Type is private; pragma Preelaborable_Initialization (Element_Type); package Queues is pragma Pure;
type Queue_Interface is limited interface;
-- Get and Put a single element from/to the queue procedure Get (Container : in out Queue_Interface; Item : out Element_Type) is abstract;
procedure Put (Container : in out Queue_Interface; Item : Element_Type) is abstract;
type Queue_Type (Capacity : Natural) is abstract new Queue_Interface with null record;
type Queue_Class_Access is access all Queue_Interface'Class;
end Queues;
Suppose that there exist two implementations of this interface.
1) A Bounded queue 2) A Queue of bounded queues that presents an abstraction of a
an array of Bounded queues as a single queue
1) Bounded Queue
generic package Queues.Bounded is
pragma Pure;
type Queue_Data (Capacity : Natural) is private; pragma Preelaborable_Initialization (Queue_Data);
type Queue (Capacity : Natural) is new Queue_Type (Capacity) with record Data : Queue_Data (Capacity); end record;
overriding procedure Get (Container : in out Queue; Item : out Element_Type); overriding procedure Put (Container : in out Queue; Item : Element_Type);
private ... end Queues.Bounded;
2) Queue of bounded Queues
generic type Queue_Array_Type is array (Natural range <>) of Queue_Class_Access; Queues : Queue_Array_Type; package Queues.Multi is
type Queue_Data (Capacity : Natural) is private; pragma Preelaborable_Initialization (Queue_Data);
type Queue (Capacity : Natural) is new Queue_Type (Capacity) with record Data : Queue_Data (Capacity); end record;
overriding procedure Get (Container : in out Queue; Item : out Element_Type); overriding procedure Put (Container : in out Queue; Item : Element_Type);
private ... end Queues.Multi;
Now suppose we want to create an instance of a queue of bounded queues. The proposed syntax allows us to write:
private with Queues.Bounded; -- Simple generic bounded queue with Queues.Multi; -- generic queue-of-bounded-queues container
package Pkg is
Maximum_Capacity : constant := 300; -- Max. no. of elements in the Q
type T is tagged private; pragma Preelaborable_Initialization (T);
-- Declare a private instantiation of the interface. package I is private new Queues (Element_Type => T);
-- NOTE: Instantiation I2 is hidden in the body
package I3 is private new I.Multi (others => private); -- Array formals hidden in body
private
type T is tagged record ... end record;
-- Instantiate interface for a queue package I is new Queues (Element_Type => T);
-- Instantiate the "low-level" bounded queue implementation capable -- of storing elements of type T package I2 is new I.Bounded;
-- Declare some queues to be used in instantiating a queue of queues Q1 : aliased I2.Queue (Capacity => 100); Q2 : aliased I2.Queue (Capacity => Maximum_Capacity - Q1.Capacity);
-- Declare types needed to instantiate queue of queues generic type Queue_Array is array (Natural range <>) of access I.Queue_Interface'Class; Queues : constant Queue_Array := Queue_Array'(1 => Q1'access, 2 => Q2'access);
-- Instantiate a queue of queues generic package I3 is new I.Multi (Queue_Array_Type => Queue_Array, Queues => Queues);
end Pkg;
!Example
Now lets look at how the proposed syntax could be applied to the examples in the problem section of this AI.
Here is the generic signature example:
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; function Size(Of_Set : Set) return Natural is <>; function Intersection(Left, Right : Set) return Set is <>; function Empty return Set is <>; function Unit_Set(With_Item : Element) return Set is <>; function Nth_Element(Of_Set : Set) return Element is <>; package Signature is new private Set_Signature (Elem, Set); private type Set is record ... end record; package Signature is new Set_Signature(Elem, Set); end Hashed_Sets;
In this case, it appears that Hashed_Sets is itself a general purpose container abstraction meant to be used on its own, and the above would be an appropriate package specification.
Suppose however, that this package were intended to be only used to create higher level abstractions by using the Signature Instantiation as a package formal to instantiate a higher level generic package. In a sense this could be considered as a type of abstract package that is not to be used on its own. In this case, we would like to be able to hide more details in the private part, and ensure that only the Signature instantiation is exported from this generic package. Using the proposed syntax, this allows us to write:
generic type Elem is private; with function Hash (El : Elem) return Integer; package Hashed_Sets is
type Set is private; package Signature is private new Set_Signature (Elem, Set, others => private);
private type Set is record ... end record; function Union (Left, Right : Set) return Set; function Size (Of_Set : Set) return Natural; function Intersection (Left, Right : Set) return Set; function Empty return Set; function Unit_Set (With_Item : Element) return Set; function Nth_Element (Of_Set : Set) return Element; package Signature is new Set_Signature (Elem, Set); end Hashed_Sets;
Here is an example where we want to instantiation a container:
package Expressions is type Expr_Ref is private; package Expr_Sequences is private new Sequences(Expr_Ref); function Operands (Expr : Expr_Ref) return access Expr_Sequences.Sequence; ... private type Expression; -- completion deferred to body type Expr_Ref is access Expression; package Expr_Sequences is new Sequences(Expr_Ref); end Expressions;
Note that being able to access the instantation in the visible part with a partial view provides a simple easy to understand solution without having to introduce incomplete types, derived types, or even named access types. Note with this proposal we also have the option of having the Operands function return an Expr_Sequences.Sequence instead of access Expr_Sequences.Sequence.
!ACATS test
ACATS B and C-Test(s) are necessary.
!appendix

From: Brad Moore
Sent: Thursday, December 11, 2008  8:56 PM

I recently encountered several issues involving generic instantiations that are
discouraging me from implementing an abstraction I have in mind.

I'm not quite sure the best way to proceed with presenting these thoughts, but I
think it might be interesting and possibly beneficial to describe my experiences
leading up to what might possibly be an alternate proposal to the "end private"
and "deferred generic freezing" solutions proposed thus far.

Please bear with me.

The problem I encountered is related to the issues being addressed by Tucker's
"end private" proposal, and Steve Baird's deferred freezing proposal, but
neither of those solutions seem to address the problems I was having.

My problem is related to the problems associated with those proposals in that I
have a visible type declared in a package specification, and I need a partial
instantiation of a generic container to support the abstraction I have in mind.

The primary issue I have is that the generic container requires some setup to
prepare the generic formal parameters, and that I want to hide the setup of the
formal generic parameters in the private part of the package.

I want to restrict visibility of this package to just the declared type and the
instantiated container as much as possible. If I have to move all the setup of
the instantiation into the public part of the package, the abstraction
deteriorates from having a simpler, cleaner interface to a rather unattractive
one.

For me, it jumped over the fence from "look what I can do in Ada!"
to "look what I had to do in Ada!".

Note: Initially, the type used to instantiate the container was not a private
type, it was just a simple record type, so I did not recognize this as being the
same issue being addressed the deferred freezing issue. In that sense, this
issue is different than the one Tucker and Steve are trying to solve. This one
can apply to both private and non-private types.

I then proceeded to think about the possible syntax changes that would be needed
to allow me to do what I wanted to do.

After some thought I came up with a potential solution and then realized that it
could also be applied to the problems that Steve Baird, and Tucker were trying
to solve.

I was getting excited by this point, thinking I had an alternate proposal that
might work.

I then went into research mode looking at past AI's and past ARG meeting minutes
to understand all the past discussions relating to partial generic
instantiation, and then discovered that what I had arrived at had mostly been
proposed before in the past.

In fact, my solution had a remarkably similar resemblance to something that was
discussed in AI95-00359-04, but never ended being part of the final proposal of
that AI.

While I am encouraged that the earlier proposal seemed to resonate well with
several people at least in some point in time and that the idea must have some
merit for it to have made it that far, I am discouraged that the idea was not
selected way back then (about 5 years ago).

Nevertheless, I think there are some differences in what I arrived at that might
avoid the wrath of Randy for dredging up past proposals. While much of what I am
proposing has been seen before in various bits and pieces from different
proposals, I did not see anywhere where all these "bits" had been packaged
together and looked at as the single solution I have in mind.

Basically, the syntax in my mind for partial generic instantiation involves
partially instantiating the generic in the visible part of the package using the
"private" keyword to indicate that the full instantiating has been moved into
the private section, analogous to how private type declarations work. In
addition, the private keyword can be also substituted for generic formal
parameters to indicate that the formal parameters are defined in the private
section.

An example of the syntax can be seen in the following;

   package I is new private Queues
       (Element_Type => T, others  => private);

The first occurrence of "private" indicates that the instantiation is a partial
instantiation.

The second occurrence indicates the formal parameter is defined in the private
section.


A stripped down version showing my example proposed usage is the following;

Basically the abstraction I am trying to present is a protected queue that is
implemented as a several several smaller queues joined together


private with Queues.Bounded;   -- A "low-level" generic bounded queue
                               --   container
private with Queues.Multi;     -- A "medium-level" generic
                               --   queue-of-queues container
with Queues.Concurrent;        -- A "high-level" container that wraps a
                               -- lower level container into a protected
                               -- type.
                               -- Note this is the only visible generic

package Pkg is

   Maximum_Capacity : constant := 300;  -- Max. no. of elements in the Q

   --  Problem A: Steve and Tuckers problem, use private type to
   --     instantiate generics
   type T is tagged private;

   function Create return T;
   pragma Preelaborable_Initialization (T);

   --  Problem B: Package subsetting: Only want to make visible the
   --  operations that operate on T, not arrays of T
   --
   --  Instantiate the generic interface (Ada 2005 interface)
   package I is new private Queues
     (Element_Type => T, others  => private);

   -- Problem C: Implementation Hiding: protected generic container
   -- storing elements of type T
   --
   --  Instantiate the protected queue of bounded queues abstraction
   package I4 is new private I.Concurrent
     (Queue_Implementation => private);


private

   --  Problem A: Instantiate a visible container with a private type.
   type T is tagged
      record
         Value : Integer := 0;
      end record;

   --  Problem B:
   --  These types are not used, but are needed to instantiate the
   --  generic interface.
   --  Hiding them in the private section makes for a simpler interface
   --  in the visible part.
   --  This ensures that the client only makes use of calls that operate
   --  on single elements and not calls that involve arrays of elements.
   --  If I decide some day to replace with a generic that does not
   --  operate on arrays, then I can replace in the private section
   --  without having to worry if clients have written code that makes
   --  calls that operate on arrays.
   type T_Index_Type is new Natural;
   type T_Array_Type is array (T_Index_Type range <>) of T;

   --  Instantiate the interface in the private section (problem B)
   package I is new Queues
     (Element_Type => T,
      Element_Index_Type => T_Index_Type,
      Element_Array_Type => T_Array_Type);

   --  Instantiate the "low-level" bounded queue implementation capable
   --  of storing elements of type T
   package I2 is new I.Bounded;

   --  Declare some queues to be used in instantiating a queue of queues
   Q1 : aliased I2.Queue (Capacity => 100);
   Q2 : aliased I2.Queue (Capacity => Maximum_Capacity - Q1.Capacity);

   --  Declare types needed to instantiate queue of queues generic
   type Queue_Array is array (Natural range <>)
     of access I.Queue_Interface'Class;
   Queues : constant Queue_Array
     := Queue_Array'(1 => Q1'Access, 2 => Q2'Access);

   --  Instantiate a queue of queues generic
   package I3 is new I.Multi
     (Queue_Array_Type => Queue_Array, Queues => Queues);

   -- Problem C: Instantiating generic needing private setup
   --  Now instantiate a protected queue of queues.
   package I4 is new I.Concurrent (Queue_Implementation => I3.Queue);

end Pkg;


I realize the use of the word "private" to represent deferred formal parameters is only cosmetically different from what Tucker had proposed years ago, where he had substituted with the box "<>" notation.

In the ARG meeting notes, he mentioned that he dropped the boxy notation from
the proposal because he felt this was too confusing. I actually had considered
using the box notation also before I discovered Tuckers past solution, but also
dropped it for the same reasons. Using "private" here I found to be quite a bit
less confusing, and more intuitive. (It does not conflict with the syntax for
default formal parameters that involves the box syntax to represent defaults.
Also it points the user to look at the private section for more details)

It is important to note that what I am proposing is not so much an alternative
to Steve Baird's proposal, as an extension to his proposal.

In other words, if the May_Be_Partial pragma is needed for Steve's proposal, it
would also be needed here. Also, the freezing and elaboration of the generic
would occur in the same place as in Steve's proposal, at the end of the
enclosing package spec, not where the instantiations occur in the private part
of the specification.

The main difference from Steve's proposal is the added syntax for the partial
instantiation, and the full instantiation of the generic in the private section.

If we are OK with Steve's proposal, maybe it's not that big a stretch to get to
this proposal from his.

>From reading the past meeting minutes, the impression I got for why the earlier
proposal was voted no action is because the ARG was running out of time and
wanted to get Ada 2005 out the door. The sense I gathered was that generally
people liked the idea, but felt it wasn't mature enough to get into Ada 2005.

Now that we are in the earlier phases of the amendment process, we now have the
benefit of Steve Baird's proposal and discussion points, and the earlier ideas
have been developed a bit further, is this approach worth considering as an
alternate/extended proposal?

The difference between this proposal and the others is that this proposal
provides a solution to all three problems shown in the code fragment above,
while the other two solutions only solve problem A.

Otherwise the differences between this proposal and the "end private" proposal
should be the same as the differences between Steve Baird's proposal and the
"end private" proposal.

Are there reasons (other than the ones I found in meeting minutes and in the
various versions of the AI) why this solution is not workable?

****************************************************************

From: Randy Brukardt
Sent: Thursday, December 11, 2008  9:26 PM

...
> Please bear with me.

No problem. You can't do any worse than we have to this point. :-)

...
> Basically, the syntax in my mind for partial generic instantiation
> involves partially instantiating the generic in the visible part of
> the package using the "private" keyword to indicate that the full
> instantiating has been moved into the private section, analogous to
> how private type declarations work. In addition, the private keyword
> can be also substituted for generic formal parameters to indicate that
> the formal parameters are defined in the private section.
>
> An example of the syntax can be seen in the following;
>
>    package I is new private Queues
>        (Element_Type => T, others  => private);
>
> The first occurrence of "private" indicates that the instantiation is
> a partial instantiation.
>
> The second occurrence indicates the formal parameter is defined in the
> private section.

I don't think the syntax was a major problem here. The major problem was with
the semantics, and you haven't said much about that.

...
...
> In other words, if the May_Be_Partial pragma is needed for Steve's
> proposal, it would also be needed here.
> Also, the freezing and elaboration of the generic would occur in the
> same place as in Steve's proposal, at the end of the enclosing package
> spec, not where the instantiations occur in the private part of the
> specification.

If you have the full instantiation in the private part, it makes the most sense
for it to work exactly as an instantiation that does not have a partial
instance. (That's surely how types work.) Thus, the elaboration and freezing
surely ought to happen at the point of the full instance. The only reason Steve
proposed doing that at the end of the package is that there is no obvious other
place that doesn't cause maintaince issues -- but that doesn't apply if there is
an explicit full instance.

> The main difference from Steve's proposal is the added syntax for the
> partial instantiation, and the full instantiation of the generic in
> the private section.
>
> If we are OK with Steve's proposal, maybe it's not that big a stretch
> to get to this proposal from his.

I think you are leaping to conclusions. See below.

> >From reading the past meeting minutes, the impression I got for why
> >the
> earlier proposal was voted no action is because the ARG was running
> out of time and wanted to get Ada 2005 out the door.
> The sense I gathered was that generally people liked the idea, but
> felt it wasn't mature enough to get into Ada 2005.

Well, there were semantic issues discussed at that Atlanta meeting. We didn't
have a clear approach to fixing them; other than reverting to my "limited
instance" proposal (see AI05-0074-1 for the most recent version of that). There
is a reason I didn't carry the partial instance version over to the Ada 2005
AIs.

> Now that we are in the earlier phases of the amendment process, we now
> have the benefit of Steve Baird's proposal and discussion points, and
> the earlier ideas have been developed a bit further, is this approach
> worth considering as an alternate/extended proposal?

Sure, but you need to propose some semantics for the partial instance. I see
none in your message, and the ones in AI95-0359-4 are known to not work.

> The difference between this proposal and the others is that this
> proposal provides a solution to all three problems shown in the code
> fragment above, while the other two solutions only solve problem A.

Right.

> Otherwise the differences between this proposal and the "end private"
> proposal should be the same as the differences between Steve Baird's
> proposal and the "end private" proposal.
>
> Are there reasons (other than the ones I found in meeting minutes and
> in the various versions of the AI) why this solution is not workable?

You haven't explained the semantics. The previous proposals for partial
instances ran into nasty semantic problems with what was exported; having only
partial visibility on things that you can then derive from (for instance) caused
all kinds of new cases in Ada. It looked like lots of odd restrictions on the
use of the instance would be needed.

The solution that I had proposed to that was to revert to my original idea of a
limited instance (not a partial instance). The idea is that the limited instance
would export the full operations (of the full instance) to clients, but would
only export a limited view (not quite exactly, but think of that as the model)
within the package. That works, but is somewhat confusing (the clients get more
than a limited view from the limited instance, but that isn't clear from the
syntax). See AI05-0074-1 for the most recent write-up of this idea.

Anyway, it's obvious that you want something else. So you need to propose
precisely what would be exported from such a partial instance. (The proposal in
AI95-0359-4 doesn't work, at least without quite a bit of additional tweaking.)
That is clearly complicated by the "private" formal parameter keyword. Formal
parameters can be used in many ways, and you would need rules for all of those
ways (I don't think you can -- or want to -- say that anything using such a
parameter is invisible; for instance, if a formal object is used in a default
expression, that's pretty much irrelevant to the use by clients of the type or
subprogram parameter with the default).

Note that the solution Steve and Ed were proposing would export *everything*
from the instance; only the freezing and elaboration rules within the package
would be changed. (The freezing changes prevent "early" use.) Complicating that
to hide some operations probably is possible, but without some details, its
impossible to say whether that even can work. (That also would allow Steve to
work his magic, and provide obscure counter-examples to break the good ideas.
:-)

I'll expect to see the complete proposal when I come in in the morning. ;-)

****************************************************************

From: Tucker Taft
Sent: Friday, December 12, 2008  12:19 AM

Very interesting ideas.  The "others => private" reads quite well.  One thing I
think is important is being able to take a type declared within an instantiation
and bring it out to the same level as the instantiation:

     package T_Vecs is new private Vectors(Element => T, others => private);
     type T_Vec is new T_Vecs.Container with null record;

Doing this requires that the parent type be completely defined, which it isn't
in this case.  If the type exported by the instantiation is tagged, you could
use a private extension:

     type T_Vec is new T_Vecs.Container with private;

which doesn't freeze the parent type.  For a non-tagged type, you would need a
post-private part or equivalent, or some relaxation in the rules for type
derivation, to be able to do this before you see the "full" instantiation.

I should probably go back and read the old proposal, but I forget how the
partial instantiation could work if you didn't specify actuals for all the
generic formals. I can't quite imagine what is the profile of any subprograms
exported by the instantiation if they use formal types that didn't have an
actual type specified. E.g.:

     package Some_Vecs is new private Vectors(others => private);

If there is an operation "Some_Vecs.Append(Vec, Element)", how could you make
any use of it since you have no idea what is the actual type associated with
"Element".  Or is it required that all type parameters be specified (possibly
with private types), but none of the other parameters?

Sounds like I have a reading assignment...

****************************************************************

From: Brad Moore
Sent: Tuesday, December 16, 2008  10:41 AM

Sorry it's been a few days for me to put a response together.
I've needed to review the various incarnations of AI05-0074, and my thoughts
have been evolving, and getting more refined. I've been thinking about freezing
quite a bit over the past few days, I think the 40 below temperatures are
providing some inspiration somehow.

I'll try to capture more details of my thoughts in this email...

> > Brad Moore Writes:
> > An example of the syntax can be seen in the following;
> >
> >   package I is new private Queues
> >       (Element_Type => T, others  => private);
> >
>
> I don't think the syntax was a major problem here. The major problem
> was with the semantics, and you haven't said much about that.

My current thoughts incorporate more of Steve Baird's proposal, and I think more
of your limited view proposal.

My idea now is that the syntax is as I have described above, except that the
word "private" is optional.

If the word "private" does not appear at all, then you essentially get the Baird
proposal. There is no explicit instantiation of the generic in the private part,
and the freezing/elaboration occur at the end of the enclosing package
specification.

If the word "private" occurs, it must at least occur after the word "new". This
means that the full instantiation occurs explicitly in the private section. The
freezing and elaboration occur after the full instantiation, the same as it does
today with normal generic instantiations.

If the word "private" occurs after the word "new", then it may also optionally
occur as a substitute for generic formal parameters.

This means that the formal(s) is/are provided in the private section, as part of
the explicit full generic instantiation.

The restrictions are that until freezing occurs, (whether implicitly at the end
of the package spec, or explicitly after the full instantiation), you cannot
create an object or an expression of anything declared in the generic spec. You
also cannot directly use any of the types declared in the generic spec as
components in an object declaration. You can however have components that are
access types that designate types in the generic spec. I think this is similar
to your limited view concept. I think from a user perspective though, it is an
easier concept to understand that the generic is partially declared and things
are being deferred to the private section, rather than thinking in terms of
being limited. I think it might make sense to use the term "limited view" in
describing the semantics for the wording in the RM, but it is better to avoid
the use of "limited" in the syntax for this purpose.

Supporting both Steve Baird's syntax and my extensions gives you the option of
having the best of both worlds.

Steve's syntax is less verbose (can be thought of as a shorthand form), but also
allows you to have multiple indirect references to generic instantiated types,
as in the following example taken from past discussions.

package P is
    type T is private;
    package T_Sets is new Sets(T);
    package T_Maps is new Maps(T);
private
    type T is record
        S : access T_Sets.Set;
        M : access T_Maps.Maps;
    end record;

    -- Problems if we are not using the Baird proposal..
    -- package T_Sets is new Sets(T);
        -- T freezes here, but T_Maps isn‘t full yet.
    -- package T_Maps is new Maps(T);
end P;

Am I correct in presuming the Baird proposal is intending to allow such an
example?

If you use the "private" syntax, then you would not be able to do this, but you
should be able to designate one of the generic instantiations as a component of
the private type. However, with the private syntax, this would allow you to
create objects and expressions from the generic specification after the freezing
point in the package, which you could not do if you are using the implicit form.

(This is a feature I need in my protected queue of queues example, that I
provided in my initial email. I declare some queue objects)

The other thing I see is a need for a change to Steve's "May_Be_Partial"
pragma.

I believe if we are to allow generic formals to be deferred to the private
section, there are potential problems if we allow the generic to derive types
from these formals. For example, a "not overriding" clause used in the generic
might conflict with a primitive subprogram declared in the private section for
the type. This would be an example of breaking privacy.

As far as I can tell, deriving types in the generic are the only places where
such problems might arise. We need someone like Steve to point out where I am
being naive, and poke other holes, but hopefully my hypothesis will hold true.

Assuming this is the case, then I think the May_Be_Partial pragma should instead
look something like;

pragma Allow (T, {Partially_Visible | Partially_Private});

The Partially_Visible has the same meaning as Steve's May_Be_Partial, and means
that the generic will not declare an object or use an expression that would
cause freezing to occur.

The Partially_Private has the same restrictions as Partially_Visible, except
that in addition, the generic cannot derive a new type from the specified formal
type.


Partially_Private means that the formal actual can be deferred to the full
instantiation in the private section. (as in; (others => private))

Partially_Visible means you cannot defer the formal actual, and that it must be
specified in the partial instantiation.

In general, to use this pragmas, you would probably want to use the
Partially_Private in most cases, unless your generic needs to derive new types
from the formals.


> > In other words, if the May_Be_Partial pragma is needed for Steve's
> > proposal, it would also be needed here.
> > Also, the freezing and elaboration of the generic would occur in the
> > same place as in Steve's proposal, at the end of the enclosing package
> > spec, not where the instantiations occur in the private part of the
> > specification.
>
>
> If you have the full instantiation in the private part, it makes the
> most sense for it to work exactly as an instantiation that does not
> have a partial instance. (That's surely how types work.) Thus, the
> elaboration and freezing surely ought to happen at the point of the
> full instance. The only reason Steve proposed doing that at the end of
> the package is that there is no obvious other place that doesn't cause
> maintaince issues -- but that doesn't apply if there is an explicit
> full instance.

Yes, I have revised my design as outlined above.


> Anyway, it's obvious that you want something else. So you need to
> propose precisely what would be exported from such a partial instance.
...
> Formal parameters can be used in many ways, and you would need rules
> for all of those ways

I think more of these details need to be provided, but before I go to that level
of detail, does what I have outlined above seem to hold some potential, or have
I already stepped off a cliff?

I plan to respond to Tucker's email separately, but I have run out of time at
the moment.

****************************************************************

From: Tucker Taft
Sent: Tuesday, December 11, 2008  10:12 PM

It would be helpful to remind us of the motivating example that got you
re-interested in this problem, and show how it could use these proposed
features. Good examples can make a big difference when it comes to deciding on
the appropriate solution.

I will say I am reluctant to have two distinct solutions to this problem.
Perhaps the two you suggest can be unified a bit so they are simply different
ways of using essentially same feature.

It would also be nice to know whether something like the "post-private" visible
part would work for your motivating example, or whether other proposals would or
would not work and why.

****************************************************************

From: Brad Moore
Sent: Wednesday, December 17, 2008  10:43 AM

> One thing I think is important is being able to take a type declared
> within an instantiation and bring it out to the same level as the
> instantiation:
>
>  package T_Vecs is new private Vectors
>    (Element => T, others => private);
>  type T_Vec is new T_Vecs.Container with null record;
>
> Doing this requires that the parent type be completely defined, which
> it isn't in this case.  If the type exported by the instantiation is
> tagged, you could use a private extension:
>
>     type T_Vec is new T_Vecs.Container with private;
>
> which doesn't freeze the parent type.  For a non-tagged type, you
> would need a post-private part or equivalent, or some relaxation in
> the rules for type derivation, to be able to do this before you see
> the "full" instantiation.

I am thinking that it should be possible to use a private extension in the
visible part of the specification as you've suggested, if you use an explicit
partial instantiation (i.e. using the "private" keyword), provided that the full
declaration comes after the full generic instantiations and the full parent type
declaration in the private part.

If you use an implicit partial instantiation (without the "private" keyword)
then you wouldn't be able to do this, because the freezing of the generics
occurs too late to declare the full declaration of the derived type.

I am currently thinking that you would not be able to do a record extension in
the visible part of the package spec involving the partial generic extension.

Does this provide enough flexibility? I think the semantics as I have described
seem to fall fairly easily from the syntax. In theory, it might be possible to
provide more flexibility (to be able to have visible record extensions involving
partial generics), but this would require more effort to define.

> I can't quite imagine what is the profile of any subprograms exported
> by the instantiation if they use formal types that didn't have an
> actual type specified.
> E.g.:
>
>     package Some_Vecs is new private Vectors(others => private);
>
> If there is an operation "Some_Vecs.Append(Vec, Element)", how could
> you make any use of it since you have no idea what is the actual type
> associated with "Element".  Or is it required that all type parameters
> be specified (possibly with private types), but none of the other
> parameters?

The idea is that you wouldn't be able to make use of this operation (in the
visible part of the package, or from outside the package), if it involved types
that were declared in the private section of a package spec.

For the most part, I would think the existing visibility rules would cover this.
You already do not have visibility to the formal parameters of a generic from
outside the generic. Also, I think the existing rules would not let you
formulate a call on such an operation, because you do not have visibility to
create an object of a type that is declared in a private section.

In the example you've given, if you want to be able to make the call
Some_Vecs.Append(Vec, Element), then you would need to ensure that the Element
type is provided visibly in the partial instantiation.

i.e.

  package T_Vecs is new private Vectors
    (Element => T, others => private);

However, you might want to hide other operations. For example, suppose you also
have an operation "Some_Vecs.Append(Vec, Array_Of_Elements)"

If the array type is one of the formal parameters to the generic, you could
declare the array type in the private section of the generic and then this
operation can not be made from outside the private section.

****************************************************************

From: Brad Moore
Sent: Wednesday, December 17, 2008  11:09 AM

> It would be helpful to remind us of the motivating example that got
> you re-interested in this problem, and show how it could use these
> proposed features.
> Good examples can make a big difference when it comes to deciding on
> the appropriate solution.

I have not shown the original motivating example yet, though I have shown a very
stripped down version of it in my first email involving a protected queue of
queues generic.

The original example I think makes a better case for these features than my
stripped down version, but is a bit more of a read. I will provide this example
shortly.

> I will say I am reluctant to have two distinct solutions to this
> problem.  Perhaps the two you suggest can be unified a bit so they are
> simply different ways of using essentially same feature.

I was thinking the two solutions can be considered as a single solution, since
they both seem to fit together well from a syntax perspective. But so far the
only real reason for having the implicit instantiation is to allow multiple
components from multiple partial instantiations as in;

package P is
    type T is private;
    package T_Sets is new Sets(T);
    package T_Maps is new Maps(T);
private
    type T is record
        S : access T_Sets.Set;
        M : access T_Maps.Maps;
    end record;

    -- Problems if we are not using the Baird proposal..
    -- package T_Sets is new Sets(T);
        -- T freezes here, but T_Maps isn‘t full yet.
    -- package T_Maps is new Maps(T);
end P;


If the implicit partial instantiation (also the Baird proposal) does not allow
this, then this part of the solution can be dropped.

Also, because the two solutions are fairly independent, we could go with one
solution for now, and decide further on down the road (Ada 2025?) to add the
other part of the solution.

I am somewhat inclined to think that we could drop the implicit partial
instantiation capability from this proposal, if everyone agreed that having
multiple components of partial instantiations is not likely to be something that
users would want to do often enough to be worthwhile.


> It would also be nice to know whether something like the
> "post-private" visible part would work for your motivating example, or
> whether other proposals would or would not work and why.

I don't believe the post-private visible part would work for example as it is
defined today, because the post private visible part does not have visibility
into the private part. The protected queue of queues example needs to see
objects declared in the private section.

I will provide more details in my next email showing the original motivating
example, and elaborate more on why the other proposals do not seem to  work well
with the problem.

****************************************************************

From: Tucker Taft
Sent: Wednesday, December 17, 2008  12:44 PM

>> I can't quite imagine what is the profile of any subprograms exported
>> by the instantiation if they use formal types that didn't have an
>> actual type specified.
>> E.g.:
>>
>>     package Some_Vecs is new private Vectors(others => private);
>>
>> If there is an operation "Some_Vecs.Append(Vec, Element)", how could
>> you make any use of it since you have no idea what is the actual type
>> associated with "Element".  Or is it required that all type
>> parameters be specified (possibly with private types), but none of
>> the other parameters?
>
> The idea is that you wouldn't be able to make use of this operation
> (in the visible part of the package, or from outside the package), if
> it involved types that were declared in the private section of a
> package spec.

What is the "private section of a package spec" in this context? Is this the
private part of the original generic, or is this somehow defined by which actual
parameters are specified as "private"?

> For the most part, I would think the existing visibility rules would
> cover this. You already do not have visibility to the formal
> parameters of a generic from outside the generic. Also, I think the
> existing rules would not let you formulate a call on such an
> operation, because you do not have visibility to create an object of a
> type that is declared in a private section.

Again, I'm not sure how you are defining "a type that is declared in a private
section" in this context.

> In the example you've given, if you want to be able to make the call
> Some_Vecs.Append(Vec, Element), then you would need to ensure that the
> Element type is provided visibly in the partial instantiation.
>
> i.e.
>
>   package T_Vecs is new private Vectors
>     (Element => T, others => private);
>
> However, you might want to hide other operations. For example, suppose
> you also have an operation "Some_Vecs.Append(Vec, Array_Of_Elements)"
>
> If the array type is one of the formal parameters to the generic, you
> could declare the array type in the private section of the generic and
> then this operation can not be made from outside the private section.

Again, I need clarification of what you mean by "private section." I presume
this is not simply the "private part" of the original generic, but is rather
related to which operations make use of formal types whose actuals are specified
as "private."

****************************************************************

From: Brad Moore
Sent: Sunday, December 21, 2008  12:04 PM

> I will say I am reluctant to have two distinct solutions to this
> problem.  Perhaps the two you suggest can be unified a bit so they are
> simply different ways of using essentially same feature.

I gave some more thought to this comment. I realized that the two solutions
could become one if the wording was changed so that 13.14(5) would not apply for
the private generic instantiation.

To better capture the semantics of the ideas I was trying to present, I started
looking at wording changes needed to implement what I had in mind. I then
realized that the part of the solution involving being able to partially
instantiate a generic and having the completed instantiation in the private part
is exactly the same thing that Randy proposed in AI05-0074-1 with the minor
difference that I was using the private keyword in the syntax where Randy was
using the word limited.

Therefore, I am factoring that part of the solution out of this proposal, and
will note that this proposal requires AI05-0074-1 as a prerequisite.

This is good because it reduces the problem set back to the original problem I
was trying to solve. (Being able to defer the declaration of generic actual
parameters to the private part of a package specification)

To capture the ideas in one place, I have written up a candidate for a new AI
(See the attached). I see this as a different AI, because it solves a different
problem than AI05-0074, but it is relevant to AI05-0074 because it can affect
the selection of proposals for that AI, and it does include some suggested minor
syntax changes for AI05-0074-1.

Writing up the proposed wording changes was a worthwhile exercise, I think,
because it strikes me that the proposed wording changes are syntactic sugar in
nature, and probably would not be difficult to implement I am guessing, assuming
that AI05-0074-1 is selected and is already implemented.

Also, please ignore my comments regarding the need for a pragma Allow in my
previous email. I came to realize that there was no need for that pragma. The
May_Be_Partial pragma of AI05-0074-3 may be useful to include in AI05-0074-1
though that is discussion that should be captured under that AI. All the
thoughts related to this proposal are hopefully captured in the attachment.

----

!subject Private Generic Actual Parameters

!summary

(See proposal.)

!problem

There are times when it would be desirable to be able to instantiate a generic
in the visible part of a package spec, yet hide implementation details or limit
the visible operations from outside the package by having the generic actual
parameters declared in the private part of the package specification.

For example:

Supposing we have a generic package that can be used to create a specific
abstraction, and we want the generic instantiation of this package to directly
provide all the operations that are available to clients in the package
containing the specific abstraction. In other words, the generic instantiation
needs to be declared in the visible part of the package associated with specific
abstraction.

Currently this requires that all the generic actuals be fully visible at the
point of the generic instantiation. It is not even possible to use a private
type as an actual of the generic. This can lead to the exposure of constants,
variable, types, subprograms, entries, and packages in the visible part of the
package that might have been better off hidden from view.

To illustrate these points, consider the following generic that provides a
template for a device driver which can be plugged into some fictional target OS.

generic
   type Device_Type is private;
   Manufacturer : String;
   Model : String;
   Disabled : in out Boolean;
   with procedure Activate_Device (Device : Device_Type);

   with function Device_Is_Operational
     (Device : Device_Type) return Boolean;
   type Configuration_Settings is private;
   with procedure Configure_Device
     (Device : Device_Type; Settings : Configuration_Settings);
package Device_Driver is

   protected Driver  is
      procedure Activate;
      function Is_Operational return Boolean;
      procedure Configure (Settings : Configuration_Settings);
   private
      Device : Device_Type;
   end Driver;
end Device_Driver;

package body Device_Driver is
   protected body Driver is

      procedure Activate is
      begin
         Activate_Device (Device);
      end Activate;

      procedure Configure (Settings : Configuration_Settings) is
      begin
         Configure_Device (Device, Settings);
      end Configure;

      function Is_Operational return Boolean is
      begin
         return Device_Is_Operational (Device);
      end Is_Operational;
   end Driver;
end Device_Driver;

Now Suppose we want to create an Audio Driver that utilizes this generic.
We really want to to expose just the calls provided by the generic to
Activate the audio driver, and to check to see if the audio driver
Is_Operational. Unfortunately, we end up having to expose a lot of
details that clients have no business looking at, and the package
specification suffers from poor readability due to the excess clutter.


with Device_Driver;
with Interfaces.C;

package Audio_Driver is

   use Interfaces;
   type Audio_Device is
      record
         Handle : C.int;
         Big_Ugly_Structure : ...
      end record;
   pragma Convention (C, Audio_Device);

   procedure Power_On (Device : Audio_Device);  -- Actual procedure
   function Playing_Music (Device : Audio_Device) return Boolean; -- Actual Function

   Muted : Boolean := False;  -- Actual Variable

   type Audio_Quality is (High, Medium, Low);
   Default_Codec : constant := 16#DEADBEEF#;
   type Audio_Settings is
      record
         Codec : C.unsigned_long := Default_Codec;
         Quality : Audio_Quality := High;
      end record;
   procedure Setup (Device : Audio_Device; Settings : Audio_Settings);
   pragma Convention (C, Audio_Settings);

   package Audio_Device_Driver is new Device_Driver
     (Device_Type => Audio_Device,  -- Actual Type
      Manufacturer => "Acme Corp",  -- Actual Constant
      Model => "SoundWhomper Mark IV", -- Actual Constant
      Disabled => Muted, -- Actual Variable
      Activate_Device => Power_On, -- Actual procedure
      Device_Is_Operational => Playing_Music, -- Actual function
      Configuration_Settings => Audio_Settings, -- Actual procedure
      Configure_Device => Setup);  -- Actual type

end Audio_Driver;

!proposal

The proposal is to select AI05-0074-1 as the solution to allow private types
to be specified as actuals for generic instantiations, and to provide new syntax
that allows actual parameters of a private generic instantiation to be left
unspecified until the completing full generic instantiation in the private
part of the package specification.

!wording

Change 12.3(4):

generic_association ::=
   [generic_formal_parameter_selector_name =>] explicit_generic_actual_parameter
{| [generic_formal_parameter_selector_name =>] private
 | others => private}

Change 12.3(6):
A generic_association is named or positional according to whether or not the generic_formal_parameter_selector_name is specified. Any positional
associations shall precede any named associations. {If there is a named
association with a generic_formal_parameter_selector_name of others, it shall
come last.}

Replace 12.3(7/2):

The generic actual parameter is one of the following:

* the explicit_generic_actual_parameter given in a generic_association
 for each formal;
* the corresponding default_expression or default_name if no generic_association
 is given for the formal;
* For a named association of a private_generic_instantiation with the reserved
 word others, all needed actual parameters from the completing
 full_generic_instantiation that at are not associated with some previous association.
* For an association of a private_generic_instantiation with the reserved word
 private but without the reserved word others, the corresponding matching
 explicit_generic_actual_parameter of the completing full_generic_instantiation.

When the meaning is clear from context, the term "generic actual," or simply
"actual," is used as a synonym for "generic actual parameter" and also for the
view denoted by one, or the value of one. A generic actual parameter of a
private generic instantiation denoted by the private keyword is called a private
generic actual parameter.

Add a note 12.3(22.1):

Where a subtype_mark of a private generic actual parameter is not visible,
subprogram calls and entry calls involving formal parameters of that
subtype_mark cannot be made. This may restrict the operations that are available
from outside the enclosing package containing the private generic instantiation.


!discussion

Unless other proposals come forward that are compatible with this AI,
this proposal requires implementing AI05-0074-1 as a prerequisite.
AI05-0074-1 solves the problem of being able to use private types
as actuals for a generic instantiation in the visible part of a
package specification, but that solution applied to the above would
still leave a lot of details exposed in the visible part of the package
that we would rather not have to expose. The Device_Type record and the
Audio_Setting record could be made into private types, hiding some of
details, but still we would have to expose the Manufacturer, the Model,
the Mute setting variable, and the various subprograms supplied as
actuals. Furthermore, this particular generic wraps a single device
object in a protected object, but otherwise does not provide any
interface to access the device object directly. Ideally, we would
not even have to expose the device object as a private type.
Suppose also that this particular audio device driver only supports one
configuration, and that the Configure call of the generic does not
do anything. Ideally, we would like to be able to hide the Configure
call from clients.

The idea is to be able to indicate that declarations for
actuals of the partial generic instantiation in the visible part of a
package specification are being deferred into the private part of a package
specification. The private keyword is used in the declaration of the
partial instantiation to indicate that a particular actual (or group
of actuals if the named association is others) is being deferred.

This AI also recommends a second use of the private keyword in the syntax.

AI05-0074-1 uses the syntax;
    limited_generic_instantiation ::=
      PACKAGE defining_identifier IS LIMITED NEW generic_package_name generic_actual_part;

While this works with this proposal, substituting the word "LIMITED" with
"PRIVATE" should also be considered as in;

    private_generic_instantiation ::=
      PACKAGE defining_identifier IS NEW PRIVATE generic_package_name generic_actual_part;

"Private" seems to better capture the idea that the instantiation is being
deferred into the private part of the package specification. It also is more
consistent with the syntax associated with private type and private extensions.
For the purpose of illustrating the examples in this AI, this alternate
variation of the syntax is assumed. This difference is only a syntactic
difference. There is no semantic difference associated with this alternative
syntax. This AI assumes that AI05-0074-1 has selected the private keyword over
the limited keyword, and this alternate syntax is not included in the wording
section of this AI. If AI05-0074-1 is selected without selecting this alternate
syntax, then this AI should be reworded to reflect the original syntax.

It was considered whether the other proposals associated with AI05-0074
would support the capabilities of this AI. The conclusion is that neither
AI05-0074-2 or AI05-0075-3 would support these features.

AI05-0074-2 is the proposal involving a second visible part of a package
that proceeds after the end of the private part of the package denoted by an
"end private" marker. This is not helpful here because any instantiation
would have to occur in the second visible part. It is not possible to
hide anything more in the private part of the package specification, and
this is further restricted because of the statement;
"The post-private visible part has no visibility on the private part."
Actuals would need to be defined in a visible part, and exposed needlessly,
although private types would allow hiding some of the details. This is the
same situation as if AI05-0074-1 was implemented, except that it precludes
the possibility of implementing this proposal.

AI05-0074-3 is the proposal involving having the instantiation in the visible
part of a package but deferring the freezing until the end of the package
specification. This solution does not help us here because there is no way
to move anything into the private part.

Note also that the problems associated with AI05-0074 involve instantiating
generics with private types. The solution of this AI can be applied to both
private and non-private types.

!example

Applying the new syntax to the example given in the problem section of this AI
allows us to write;

with Device_Driver;
private with Interfaces.C;

package Audio_Driver is
   package Audio_Device_Driver is new private Device_Driver (others => private);

   -- These renamed subprograms are the only visible operations
   procedure Activate renames Audio_Device_Driver.Driver.Activate;
   function Is_Operational return Boolean renames Audio_Device_Driver.Driver.Is_Operational;

   --  Note Audio_Device is more private than if we had declared it as a private type.
   --  You cannot even declare an Audio Device, or call Power_On, or Playing_Music directly
   --  But you can call Audio_Device_Driver.Activate, or Audio_Device_Driver.Is_Operational
   --  to do the same thing.
   -- Note you cannot call Configure because the type associated with one of the formal parameters
   -- of that call (Audio_Settings) is not visible.

private

   use Interfaces;
   type Audio_Device is
      record
         Handle : C.int;
         Big_Ugly_Structure : ...
      end record;
   pragma Convention (C, Audio_Device);

   procedure Power_On (Device : Audio_Device);  -- Actual procedure
   function Playing_Music (Device : Audio_Device) return Boolean; -- Actual Function

   Muted : Boolean := False;  -- Actual Variable

   type Audio_Quality is (High, Medium, Low);
   Default_Codec : constant := 16#DEADBEEF#;
   type Audio_Settings is
      record
         Codec : C.unsigned_long := Default_Codec;
         Quality : Audio_Quality := High;
      end record;
   procedure Setup (Device : Audio_Device; Settings : Audio_Settings);
   pragma Convention (C, Audio_Settings);

   package Audio_Device_Driver is new Device_Driver
     (Device_Type => Audio_Device,  -- Actual Type
      Manufacturer => "Acme Corp",  -- Actual Constant
      Model => "SoundWhomper Mark IV", -- Actual Constant
      Disabled => Muted, -- Actual Variable
      Activate_Device => Power_On, -- Actual procedure
      Device_Is_Operational => Playing_Music, -- Actual function
      Configuration_Settings => Audio_Settings, -- Actual procedure
      Configure_Device => Setup);  -- Actual type

end Audio_Driver;

This dramatically simplifies the visible part of the package specification.

Now suppose, we want to allow clients to access the mute variable which is
supplied as an actual.

The visible part of the package specification would then look like;

package Audio_Driver is

   Muted : Boolean := False;  -- Actual Variable

   package Audio_Device_Driver is new private Device_Driver
            (Disabled => Muted, others => private);
...

Clients can mute the sound simply by modifying the Muted variable. This seems to
better separate the actual variable from the instantiated abstraction.

Now suppose we want to support multiple configurations, and allow clients
to be able to use of the Configure call.
This can be accomplished by modifying the visible part of the package
to look like;

package Audio_Driver is

   Muted : Boolean := False;

   type Audio_Settings is private;

   package Audio_Device_Driver is new private Device_Driver
            (Disabled => Muted,
             Configuration_Settings => Audio_Settings,
             others => private);
...


!ACATS test

ACATS B and C-Test(s) are necessary.

****************************************************************

From: Brad Moore
Sent: Sunday, December 21, 2008  12:09 PM

One of the advantages of the AI05-0074-2 proposal (end private) that is missing
from the other proposals of that AI is that it is possible to declare a derived
non-tagged type from a type exported in the private generic instantiation that
is visible outside the package. We run into freezing problems if we try to do
this with the current proposals involving AI05-0074-1.

eg.
generic
  Y : private;
  X : Integer;
  Z : String;
 ...
package A_Container is
  type Q is null record;
end A_Container;

with A_Container;
package Foo
  type T is private;
  package I is new private A_Container(T, others => private);
  type D is new I.Q; -- ERROR: Freezing problem here private
  type T is null record;
  package I is new A_Container(T, 1, "I Container", ...); end Foo;

To solve this problem with this version of the AI, would it be worth considering
allowing the syntax for type extensions to also be applied to non-tagged types?

This would allow non-tagged types to be completed at the correct place in the
private part similar to how it works for tagged type extensions.

e.g.
with A_Container;
package Foo
  type T is private;
  package I is new private A_Container(T, others => private);
  type D is new I.Q with private; --  Type extension for non-tagged type private
  type T is null record;
  package I is new A_Container(T, 1, "I Container", ...);
  type D is new I.Q;
end Foo;

****************************************************************

From: Brad Moore
Sent: Friday, January 2, 2009  1:03 PM

Randy pointed out to me that a limited view of a type precludes the ability to
derive new types, whereas I was going for a solution that allows such
derivations. In order to do that, a partial view rather than a limited view is
needed.

e.g.,

with Ada.Containers.Doubly_Linked_Lists;
package Pkg is
  type T is private;
  package T_List is new private Ada.Containers.Doubly_Linked_List(T);
  type List_Type is new T_List.List; -- Partial View needed here private
  type T is null record;
  package T_List is new Ada.Containers.Doubly_Linked_List(T);
end Pkg;

While the proposed syntax for private generic actuals seems to be compatible
with the solution of AI05-0074-1, and could possibly be considered as an option
to that solution, I wanted to aim for a solution that also covers the other
problems mentioned in the other proposals. Randy suggested I create a new
proposal for AI05-0074, that incorporates a partial view which I have done. (See
attached)

I have also incorporated a few more ideas. Now in addition to being able to
declare private types, private extensions, and private instantiations, you can
also declare private objects. Also, this proposes a way to declare private
extensions for untagged types.

The proposed wording changes are mostly confined to section 7.3 in the RM. I
think the wording probably needs some more polish but hopefully it is clear
enough that the semantics can be understood.

----

!subject Private Generic Actual Parameters

!summary

(See proposal.)

!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

- Introduce new syntax (a private_instantiation_declaration) that allows
an incomplete declaration of a generic package instantiation to be made in
the visible part of a package specification and completed with a
generic_instantiation in the private part of the package.

- In the region between the private_instantiation_declaration and the
generic_instantiation in the package specification, implicitly declare
limited and private views of all type declarations from the
generic_instantiation that are accessible from outside the
generic_instantiation. The limited views apply only to any
record_definition associated with a type declaration in this region.
Otherwise the partial view of these type declarations are available in
this region.

- In the region between the completing generic_instantiation and the
end of the package specification, and from views outside the package
specification, the full view of the generic instantiation applies.

- A new pragma (May_Be_Partial) is defined that must be applied to
any generic formal declarations for which the actual may be a partial
view named in a private_instantiation_declaration. This pragma restricts
the usage of the formal within the generic package to not allow any
constructs that would require freezing of the formal type. In particular,
this means that an object or an expression of the type cannot be used
in the package specification, nor can new types be derived from these
generic formals within the package specification.

- To allow type derivations of untagged partial views named in a
private_instantiation_declaration within the same visible part of
a package specification, a private_extension is allowed to apply
to both tagged and untagged types.

- Allow a private_instantiation_declaration to be able to specify that any
actual parameters can be left unspecified until the private part of the package
specification.

- Add new syntax to allow a variable of a private type or private extension
to be exported from a package.

!wording

Change the title of Section 7.3:
Private Types{,}[and] Private Extensions{, Private Objects, and Private
Instantiations}

Change 7.3(1):

The declaration (in the visible part of a package) of a type as a private
type or private extension {or of a generic instantiation as a private
instantiation} serves to separate the characteristics that can be used
directly by outside program units (that is, the logical properties) from
other characteristics whose direct use is confined to the package
[(the details of the definition of the type itself)]. See 3.9.1 for an
overview of type extensions.

Add 7.3(3.1-3.4):

3.1 private_object_declaration ::=
    defining_identifier_list : [ALIASED] [CONSTANT] PRIVATE subtype_indication;
  | defining_identifier_list : [ALIASED] [CONSTANT] PRIVATE array_type_definition;

3.2 private_instantiation_declaration ::=
   PACKAGE defining_program_unit_name IS
         NEW PRIVATE generic_package_name [deferred_generic_actual_part];

3.3 deferred_generic_actual_part ::=
   (deferred_generic_association {, deferred_generic_association})

3.4 deferred_generic_association ::=
   [generic_formal_parameter_selector_name =>]  explicit_generic_actual_parameter
 |  [generic_formal_parameter_selector_name =>] PRIVATE
 | others => PRIVATE

3.5 A deferred_generic_association is named or positional according to whether
or not the generic_formal_parameter_selector_name is specified. Any positional
associations shall precede any named associations. If there is an association
with the reserved word OTHERS, it shall come last.

Add 7.3(4.1-4.10):

4.1 A private_object_declaration declares a view of an object. The view is an
aliased view if the ALIASED keyword is associated with the declaration. The view
is a constant view if the CONSTANT keyword is associated with the declaration.
Such a declaration is allowed only as a declarative_item of the visible part of
a package, and it requires a completion, which shall be an object_declaration
that occurs as a declarative_item of the private part of the package. The view
of the private_object_declaration is a view of the completed object_declaration.
The view can only be referenced from outside the package specification.

4.2 The named object of a private_object_declaration shall either be an object
associated with a private type or private extension declared within the visible
part of the package specification containing the private_object_declaration, or
an array whose component's are of a type that is associated with a private type
or private extension declared within the visible part of the package
specification containing the private_object_declaration.

4.3 The subtype_indication of a private_object_declaration shall statically
match the subtype_indication in the completing declaration.

4.4 If the private_object_declaration includes the reserved word ALIASED, then
the completing declaration shall also.

4.5 If the subtype of the private_object_declaration excludes null, the subtype
of the completing declaration shall also exclude null.

4.6 A private_instantiation_declaration implicitly declares a partial view
and a limited view of all type declarations of the generic package associated
with the instantiation that are visible from outside the completed generic
instantiation. A private_instantiation_declaration also declares a full view
of the completed generic instantiation. The applicable set of views is
determined by context, but no more than one set of views (either the partial
views, the limited views, or the full view) may apply to any given context.

4.7 A private_instantiation_declaration is allowed only as a declarative_item
of the visible part of a package, and it requires a completion, which shall be
a generic_instantiation (see 12.3) that occurs as a declarative_item of the
private part of the package.

4.8 The actual parameters of the completion shall match the corresponding actual
parameters of the private_instantiation_declaration, whether the actual parameters
are given explicitly or by default.

4.9 The rules for matching of actual parameters between the completion and the
private instantiation are as follows:

4.10   * If an association is a named association in the private instantiation
 then the association shall be a named association in the completion. If an
 association is a positional association in the private instantiation then the
 association shall be positional in the completion.

4.11   * A named association with the reserved word OTHERS matches all needed
 actual parameters from the completing generic_instantiation that are not
 associated with some previous association. This includes the corresponding
 default_expression or default_name of a formal if no generic_association is
 given for the formal in the completing generic instantiation;

4.12  * An association with the reserved word PRIVATE but without the reserved
 word OTHERS matches the actual of the completing generic instantiation that has
 the same  generic_formal_parameter_selector_name if the association is a named
 association, or the actual in the corresponding relative position within the
 generic_actual_part if the association is a positional association.

4.13   * 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.

4.14   * For a formal subtype, the actuals match if they denote statically
 matching subtypes.

4.15  * For other kinds of formals, the actuals match if they statically
 denote the same entity.

AARM NOTE: We considered using full conformance rules here instead of
    formal-package-ish matching. However, we wanted to use rules consistent
    with formal packages, and it seemed simpler to just define the particular
    matching rules needed between instantiations. Also we wanted to
    ensure that no evaluations would take place at the point of the
    private instantiation.}

Change 7.3(5):
A type shall be completely defined before it is frozen (see 3.11.1 and 13.14).
Thus, neither the declaration of a variable of a partial view of a type, nor
the creation by an allocator of an object of the partial view are allowed before
the [full] declaration {providing the full view} of the type. Similarly, before
the full declaration, the name of the partial view cannot be used in a
generic_instantiation or in a representation item. {If the name of a partial
view is used in a private_instantiation_declaration then the generic formal
parameter of the completing generic_instantiation shall have the May_Be_Partial
pragma applied to it. See 12.3.1}

Change 7.3(6/2):
A private type is limited if its declaration includes the reserved word limited;
a private extension is limited if its ancestor type is a limited type that is not
an interface type, or if the reserved word limited or synchronized appears in its
definition. If the partial view is nonlimited, then the full view shall be
nonlimited. If a tagged partial view is limited, then the full view shall be limited.
On the other hand, if an untagged partial view {of a private type} is limited, the
full view may be limited or nonlimited.

Change 7.3(7):
If the partial view is tagged, then the full view shall be tagged. On the other
hand, if the partial view is untagged, then the full view may be tagged or untagged.
In the case where the partial view is untagged and the full view is tagged, no
derivatives of the partial view are allowed within the immediate scope of the
partial view {unless the derivative is a private_extension_declaration};
derivatives of the full view {do not have this restriction}[are allowed].

Change 7.3(8):
The ancestor subtype of a private_extension_declaration is the subtype defined
by the ancestor_subtype_indication; the ancestor type shall be a specific [tagged]
type. The full view of a private extension shall be derived (directly or
indirectly) from the ancestor type. In addition to the places where Legality Rules
normally apply (see 12.3), the requirement that the ancestor be specific applies
also in the private part of an instance of a generic unit.

Add 7.3(15.1):

15.1 The implicit declaration of partial views and limited views, and the full
view of the generic_instantiation define three sets of views associated with a
private_instantiation_declaration. The limited views define the allowed usage
within a component_list of any record_definition declared between the
private_instantiation_declaration in the visible part and the completed
generic_instantiation in the private part of a package specification; otherwise,
the partial views define the allowed usage for the same region of a package
specification. The full view together with the visible part define the
operations that are available to outside program units. The full view together
with the private part define other operations whose direct use is possible only
within the declarative region of the package itself between the completing generic
instantiation and the end of the declarative region.

Change 7.3(17):
The elaboration of a private_type_declaration creates a partial view of a type.
The elaboration of a private_extension_declaration elaborates the
ancestor_subtype_indication, and creates a partial view of a type.
{The elaboration of a private_object_declaration elaborates the subtype_indication
or the array_type_definition. The elaboration of a private_generic_instantiation
creates limited and partial views for all type declarations of the generic package
associated with the instantiation that are visible from outside the completed
generic instantiation. The elaboration also creates a full view of the
generic instantiation.}

Add 7.3(20.2):

The completing object_declaration for a private_object_declaration is not allowed
before the corresponding full_type_declaration of the private_type or
private_extension. This is a consequence of the freezing rules for types (see 13.14).

Add 7.3(20.3):
If a private_instantiation_declaration is referenced from outside the package
specification and the completed generic_instantiation is not visible, then any
generic actual parameters that were declared in the private part of the package
are not visible and therefore cannot be referenced. Any subprograms or entries
declared visibly in the generic that have formal parameters of a non-visible
formal type declared in the private part of the package containing the
private_instantiation_declaration cannot be called from a context where the
private part of the package is not visible.

Add new section 12.3.1:

12.3.1 Actual Types With Partial Views

1 This subclause defines a pragma that allow a private_instantiation_declaration
to use a name of a partial view.

Syntax

2 The form of a pragma May_Be_Partial is as follows:

3 pragma May_Be_Partial(direct_name);

Legality Rules

4   The pragma May_Be_Partial specifies that a formal type may correspond to a
generic_instantiation that is associated with a
private_instantiation_declaration for which the matching actual is a partial
view. The formal type associated with the pragma shall not be used in a context
within the generic package specification that would require freezing of the type
(See 13.14, “Freezing Rules”). This pragma shall appear in a generic_formal_part
and the direct_name shall denote a generic formal private type or a generic
formal derived type declared in the same generic_formal_part as the pragma.

Change 13.14(5):
The occurrence of a generic_instantiation causes freezing {unless the instantiation
has a corresponding private_generic_instantiation}; also, if a parameter of the
instantiation is defaulted, the default_expression or default_name for that
parameter causes freezing.

Change 13.14(8/1):
A static expression causes freezing where it occurs. An object name or nonstatic
expression causes freezing where it occurs, unless the name or expression is
part of a default_expression, a default_name, {a private_generic_instantiation,
a generic_instantiation that has a corresponding private_generic_instantiation,}
or a per-object expression of a component's constraint, in which case, the
freezing occurs later as part of another construct.


!discussion

This proposal solves several problems that come up frequently in practice with
private types. Certainly the most common is a desire to include an instantiation
of a generic (possibly a signature generic as mentioned in the "problem" section
above, or perhaps a container generic), with a private type as one of the actual
parameters to the instantiation. Another problem is a desire to export a
variable of a private type. This is not permitted prior to the private type
being completed. A third problem is a desire to derive a new type from an
untagged private type in the visible part of the package that declared the
untagged private type. Tagged types can declare a private extension, but there
is no corresponding syntax to declare a private extension of an untagged type. A
fourth problem is a desire to derive a new type in the visible part of a package
from a type (tagged or untagged) that is declared in a generic package that is
instantiated in the same visible part of the package, where the generic is
instantiated with a private type or private extension. A fifth problem is a
desire to be able to have a type declaration that contains an access to an
instantiated type of a generic whereby the type declaration was supplied as an
actual for the instantiation. An instantiation requires the type to be defined
first, but if the instantiation comes after the type declaration, then the type
declaration cannot name any type declarations of the instantiation.  A sixth
problem is a desire to instantiate a generic in the visible part of a package,
yet defer the declarations for some or all of the actuals to the private part of
the package. A seventh problem is a desire to have a way to make certain
operations of a generic unavailable for use if they do not support the
particular abstraction associated with the instantiation.

The basic idea of this proposal is to add syntax that provides more ways to
create incomplete declarations in the visible part of a package specification
that are completed in the private part of the package thus providing more
flexibility and capabilities for exporting functionality in the visible part
of a package specification.

This is limited to packages because you can use renaming-as-body to get this
effect for subprogram instantiations. Moreover, you cannot export a type from
a generic subprogram, so there is no possibility of recursive use.
[Note that we could lift this limitation if it if felt to be more regular.]

Ada 2005 provides solutions to these problems, but they are not ideal.
For the first example, making the instantiation a child unit solves the problem.
However, this is annoying, because accessing the instance requires an extra with
and instantiation (since children of generics must be generic):

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;
   ...
private
   type Set is record ... end record;
end Hashed_Sets;

generic
package.Hashed_Sets.Signature is
   package The_Signature is new Set_Signature(Elem, Set);
end Hashed_Sets.Signature;

A user of Hashed_Sets must with and instantiate Hashed_Sets.Signature in order
to access the instance. The second problem can also be solved with child units,
using the limited with:

limited with Expressions.Sequences;
package Expressions is
   type Expr_Ref is private;
   type Seq_Of_Expr is access Expressions.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;

package Expressions.Sequences is
   package Expr_Sequences is new Sequences(Expr_Ref);
   type Sequences is Expr_Sequences.Sequence;
end Expressions.Sequences;

Here, besides the extra with clause, we need to declare an extra type
simply so that the type is visible to the limited with clause
(which operates purely syntactally). This means that extra type conversions
are necessary.

The most important capability is to be able to instantiate a generic with a
private type or private extension as an actual. The concept is to be able
to declare a generic instantiation in two parts. The first part is called
a private_generic_instantiation and is declared in the visible part of a package
specification. The second part is the completing generic_instantiation that
occurs in the private part of the package specification. The instantiation in
the private part is the real instantiation. The syntax in the visible part
really just provides a view of the instantiation that is exported.

e.g.,
   with Ada.Containers.Doubly_Linked_Lists;
   package Pkg is
      type T is private;
      package I is new PRIVATE Ada.Containers.Doubly_Linked_Lists (T);
   private
      type T is null record;
      package I is new Ada.Containers.Doubly_Linked_Lists (T);
   end Pkg;

   The intent is that the exported view of the instantiation of I is effectively
   the same as the view if the generic had been instantiated from outside the
   Pkg;

i.e.

   package Pkg is
      type T is private;
   private
      type T is null record;
   end Pkg;

   with Pkg; use Pkg;
   with Ada.Containers.Doubly_Linked_Lists;
   procedure Use_Pkg is
      package I is new Ada.Containers.Doubly_Linked_Lists (T);
   begin
      ...
   end Use_Pkg;

Now suppose we would like to have type T include an access to a type
provided by the instantiation. There is no way to do this currently
in Ada. It is possible to use an incomplete type, and then complete
this type with a derivation from a type provided by the instantiation.
e.g.,

   with Ada.Containers.Doubly_Linked_Lists;
   package Pkg is
      type T is private;
   private
      type List_Type;
      type T is
        record
          List : access List_Type;
        end record;
      package I is new Ada.Containers.Doubly_Linked_Lists (T);
      type List_Type is new I.List with null record;
   end Pkg;

However it is not always possible to derive a new type. Supposing
we decided to use a different container based on a protected type.

   with Ada.Containers.Protected_Queue; -- A new container currently being proposed.
   package Pkg is
      type T is private;
   private
      type Queue_Type;
      type T is
        record
          Queue : access Queue_Type;
        end record;
      package I is new Ada.Containers.Protected_Queue (T);
      type Queue_Type is new I.Queue with null record;
      -- ERROR Cannot derive a new type from a protected type or interface.
   end Pkg;

Using the new syntax however, this becomes possible, and simpler,
because the generic has been already been named in a
private_instantiation_declaration. Note there is no longer a need to declare
an incomplete type. There is also no longer a need to derive a new type
from the instantiation.

e.g.,

   with Ada.Containers.Protected_Queue; -- A new container currently being proposed.
   package Pkg is
      type T is private;
      package I is new private Ada.Containers.Protected_Queue (T);
   private
      type T is
        record
          Queue : access I.Queue;
        end record;
      package I is new Ada.Containers.Protected_Queue (T);
   end Pkg;


For this to work, only a limited view of the instantiated package
is needed. By saying that the view of the instantiated types within
the record_declaration is a limited view, it avoids problems with
recursive declarations by ensuring that only access types may be used
to name the instantiated types.

Now suppose we want this example to export two containers instantiated
from the same type.

e.g.,
   with Ada.Containers.Doubly_Linked_Lists;
   with Ada.Containers.Protected_Queue;
   package Pkg is
      type T is private;
      package I1 is new private Ada.Containers.Protected_Queue (T);
      package I2 is new private Ada.Containers.Doubly_Linked_Lists (T);
   private
      type T is
        record
          Queue : access I1.Queue;
          List : access I2.List;
        end record;
      package I1 is new Ada.Containers.Protected_Queue (T);
      package I2 is new Ada.Containers.Doubly_Linked_Lists (T);
      -- ERROR FREEZING Problem here. I1 instantiation freezes T. (See 13.14(5))
   end Pkg;

We would like to be able to instantiate the above without running into
freezing problems. To achieve this goal, we need to relax the freezing
rules so that instantiations associated with private_instantiation_declarations
do not cause freezing to occur. It should be possible to not have 13.14(5) apply
so that freezing occurs at the next freezing point instead.

To avoid freezing problems in the generic, we also need to ensure that the
generic does not have any declarations that would cause freezing of the formal
whereby the corresponding actual is a private type or private extension. In
particular, we need to ensure that the generic does not declare any objects of
the formal type, or have any expressions involving the formal type in the
package specification. In addition, the generic cannot derive a new type from
the formal, because of 13.14(7). We also want to have a way to make it explicit
that a formal could be a partial type, so that maintenance of a generic package
wont introduce changes that could cause compilations to fail. To address this
need, a new pragma is introduced, pragma May_Be_Partial, which may be applied to
a generic formal type, and makes it explicit that the associated formal type
will not be used in a way that would cause freezing of that type within the
generic specification and body.

For example, if we were to apply this pragma to the
Ada.Containers.Doubly_Linked_List package, it would appear as;

generic
   type Element_Type is private;
   pragma May_Be_Partial (Element_Type);

   with function "=" (Left, Right : Element_Type)
      return Boolean is <>;

package Ada.Containers.Doubly_Linked_Lists is
   ...


Now consider that we would like to be able to export a derived type of an
instantiated type associated with a private_instantiation_declaration. For
this to work, a private_extension must be used because otherwise a type
derivation would cause freezing to occur. This is fine, but we run into
problems with a limited view.

e.g.,
   with Ada.Containers.Doubly_Linked_Lists;
   with Ada.Containers.Protected_Queue;
   package Pkg is
      type T is private;
      package I1 is new private Ada.Containers.Protected_Queue (T);
      package I2 is new private Ada.Containers.Doubly_Linked_Lists (T);
      type New_List is new I2.List with private;
      --  ERROR if view of I2 is a limited view!
   private
      type T is
        record
          Queue : access I1.Queue;
          List : access I2.List;
        end record;
      package I1 is new Ada.Containers.Protected_Queue (T);
      package I2 is new Ada.Containers.Doubly_Linked_Lists (T);
      type New_List is new I2.List with null record;
   end Pkg;

A limited view of a type is a very restricted view and does not allow
type derivations. To be able to do this, we need a partial view of the type.
However, we want a limited view within record definitions. To get around this
we say that a private_instantiation_declaration declares 3 sets of views.
There is a set of limited views of all type declarations exported from the
instantiation, there is a set of partial views of all type declarations
exported form the declaration, and there is the full view of the instantiation.

The limited and private views only apply to the package specification and
together cover the region in the package specification between the
private_instantiation_declaration and the completing generic_instantiation. The
limited views only apply to record_definitions within this region, whereas the
partial views apply everywhere else within this region. The full view applies to
the region between the generic_instantiation and the end of the package
specification, and also outside of the package;

It was considered whether we could say only partial views are created, instead
of both limited and partial views, and then special rules could be added to
ensure that only access types are used within record definitions, but it seemed
that it was easier and safer to say that a limited view applied in such a
context instead.

Currently the wording of this proposal only creates views of type
declarations that are externally visible from the instantiation. The wording
does not create views for subtype declarations. The reasons for this are that
it seems like there would be less likely to be problems if we leave subtype
declarations out of the picture. A limited view of a package does not see
subtype declarations, and it seems simpler if the limited and partial views
are for the same set of declarations. Note that limited and partial views
are also provided for any visible instantiations declared within the generic
being instantiated.

Now consider that we would like to also derive from an untagged type. We need
to declare a type extension, but there is no such thing for an untagged type.

e.g.,

   with Ada.Containers.Doubly_Linked_Lists;
   with Ada.Containers.Protected_Queue;
   package Pkg is
      type T is private;
      package I1 is new private Ada.Containers.Protected_Queue (T);
      package I2 is new private Ada.Containers.Doubly_Linked_Lists (T);
      type New_Cursor is new I2.Cursor;
      --  ERROR a type derivation causes freezing!
   private
      type T is
        record
          Queue : access I1.Queue;
          List : access I2.List;
        end record;
      package I1 is new Ada.Containers.Protected_Queue (T);
      package I2 is new Ada.Containers.Doubly_Linked_Lists (T);
   end Pkg;

To get around this, we need a way to declare a private derivation for an
untagged type. Rather than create new syntax, it is proposed that we use
the same syntax as for tagged types, but allow a private_extension to
be used for both tagged and untagged types.

e.g.,

   with Ada.Containers.Doubly_Linked_Lists;
   with Ada.Containers.Protected_Queue;
   package Pkg is
      type T is private;
      package I1 is new private Ada.Containers.Protected_Queue (T);
      package I2 is new private Ada.Containers.Doubly_Linked_Lists (T);
      type New_List is new I2.List with private;      -- private extension for a tagged type
      type New_Cursor is new I2.Cursor with private;  -- private extension for an untagged type
   private
      type T is
        record
          Queue : access I1.Queue;
          List : access I2.List;
        end record;
      package I1 is new Ada.Containers.Protected_Queue (T);
      package I2 is new Ada.Containers.Doubly_Linked_Lists (T);
      type New_List is new I2.List with null record;  -- Completion of tagged private extension
      type Cursor is new I2.Cursor;                   -- Completion of untagged private extension
   end Pkg;

The use of "with private" might seem to conflict a bit for the case of an
untagged type as it suggests an extension to the record structure, but this
could be possibly rationalized as it is possible to add more primitives in the
private part, and could be thought of as being extended by an implicit null
record. It seemed better to use the same syntax for both, rather than invent new
syntax that applies specifically to untagged types.

Now suppose we want to export a variable of a private type or a private
extension. This is currently not possible in Ada.

e.g.,

   package Pkg is
      type T is private;
      Global_List : T;
      --  ERROR the variable declaration freezes T!
   private
      type T is null record;
   end Pkg;

To get around this, we take a similar approach as we did for generic
instantiations. We add syntax to allow an incomplete object declaration
in the visible part of a package specification that is completed by an
object_declaration in the private part;

e.g.,

   package Pkg is
      type T is private;
      Global_List : private T;  -- private_object_declaration
      Global_Array : private array (1 .. 5) of T;
   private
      type T is null record;
      Global_List : T;          -- completing object_declaration
      Array_Of_T : array (1 .. 5) of T;
   end Pkg;

In this case, we say that the private_object_declaration is a *view* of an
object, not an object declaration. The view is that of the completing object
declaration.

A private_object_declaration may use the ALIASED or CONSTANT keyword.
If ALIASED appears in the private_object_declaration, it must also
appear in the completing object declaration. The CONSTANT keyword
does not need to appear in the completing object_declaration if it
appears in the private_object_declaration however. In this case,
the exported view is a constant view, but may be variable within
the private part. To simplify things, it is proposed
that the private_object_declaration can only be referenced from
outside the package specification. In theory, it should be possible
to create wording that allows an aliased variable to be referenced
within the package specification, but it seems that this would be
tricky to get right. For now, it seems best to only allow references
to private_object_declarations from outside the package specification.
Also, it only seemed to be worthwhile to allow objects, or arrays of
objects to be defined in a private_object_declaration. For example,
an access to object declaration can be setup in Ada today, in the
elaboration of a package body.

The proposed rules state that a private_object_declaration can only
be applied to a private type or private extension, or to an array
of objects of a private type or private extension.

Note also that a constant private_object_declaration is very
similar to a deferred constant declaration. There are a few differences
however. A deferred constant can be combined with pragma import, to
link to an external value. Also, a deferred constant does not need to
be of a private type, or of a private extension. It seemed worthwhile
to provide the constant view of a private_object_declaration even if
it does overlap with a deferred constant somewhat.

Now suppose we would like to be able to hide more details associated
with a private_instantiation_declaration in the private part of a package
specification. In particular, we want to be able to declare certain actuals
in the private part, instead of having to declare them in the visible part
of a package specification. It may also be desirable to limit the visible
operations from outside the package by having the generic actual parameters
declared in the private part of the package specification.

For example:

Supposing we have a generic package that can be used to create a specific
abstraction, and we want the generic instantiation of this package to
directly provide all the operations that are available to clients in the
package containing the specific abstraction.

In other words, the generic instantiation needs to be declared in the
visible part of the package associated with specific abstraction.

Currently this requires that all the generic actuals be fully visible
at the point of the generic instantiation. This can lead to the
exposure of constants, variable, types, subprograms, entries, and
packages in the visible part of the package that might have been better
off hidden from view.

To illustrate these points, consider the following generic that provides
a template for a device driver which can be plugged into some fictional
target OS.

generic
   type Device_Type is private;
   Manufacturer : String;
   Model : String;
   Disabled : in out Boolean;
   with procedure Activate_Device (Device : Device_Type);

   with function Device_Is_Operational
     (Device : Device_Type) return Boolean;
   type Configuration_Settings is private;
   with procedure Configure_Device
     (Device : Device_Type; Settings : Configuration_Settings);
package Device_Driver is

   protected Driver  is
      procedure Activate;
      function Is_Operational return Boolean;
      procedure Configure (Settings : Configuration_Settings);
   private
      Device : Device_Type;
   end Driver;
end Device_Driver;

package body Device_Driver is
   protected body Driver is

      procedure Activate is
      begin
         Activate_Device (Device);
      end Activate;

      procedure Configure (Settings : Configuration_Settings) is
      begin
         Configure_Device (Device, Settings);
      end Configure;

      function Is_Operational return Boolean is
      begin
         return Device_Is_Operational (Device);
      end Is_Operational;
   end Driver;
end Device_Driver;

Now Suppose we want to create an Audio Driver that utilizes this generic.
We really want to to expose just the calls provided by the generic to
Activate the audio driver, and to check to see if the audio driver
Is_Operational. Unfortunately, we end up having to expose a lot of
details that clients might have no business looking at, and the package
specification suffers from poor readability due to the excess clutter.


with Device_Driver;
with Interfaces.C;

package Audio_Driver is

   use Interfaces;
   type Audio_Device is
      record
         Handle : C.int;
         Big_Ugly_Structure : ...
      end record;
   pragma Convention (C, Audio_Device);

   procedure Power_On (Device : Audio_Device);  -- Actual procedure
   function Playing_Music (Device : Audio_Device) return Boolean; -- Actual Function

   Muted : Boolean := False;  -- Actual Variable

   type Audio_Quality is (High, Medium, Low);
   Default_Codec : constant := 16#DEADBEEF#;
   type Audio_Settings is
      record
         Codec : C.unsigned_long := Default_Codec;
         Quality : Audio_Quality := High;
      end record;
   procedure Setup (Device : Audio_Device; Settings : Audio_Settings);
   pragma Convention (C, Audio_Settings);

   package Audio_Device_Driver is new Device_Driver
     (Device_Type => Audio_Device,  -- Actual Type
      Manufacturer => "Acme Corp",  -- Actual Constant
      Model => "SoundWhomper Mark IV", -- Actual Constant
      Disabled => Muted, -- Actual Variable
      Activate_Device => Power_On, -- Actual procedure
      Device_Is_Operational => Playing_Music, -- Actual function
      Configuration_Settings => Audio_Settings, -- Actual procedure
      Configure_Device => Setup);  -- Actual type

end Audio_Driver;


The Device_Type record and the Audio_Setting record could be made
into private types, hiding some of details, but still we would have
to expose the Manufacturer, the Model, the Mute setting variable,
and the various subprograms supplied as actuals. Furthermore, this
particular generic wraps a single device object in a protected
object, but otherwise does not provide any interface to access
the device object directly. Ideally, we would not even have to
expose the device object as a private type.

Suppose also that this particular audio device driver only supports one
configuration, and that the Configure call of the generic does not
do anything. Ideally, we would like to be able to hide the Configure
call from clients.

The idea is to be able to indicate that declarations for
actuals of the partial generic instantiation in the visible part of a
package specification are being deferred into the private part of a package
specification. The private keyword is used in the declaration of the
private_instantiation_declaration to indicate that a particular actual
(or group of actuals if the named association is others) is being deferred
to the private part of the package specification.

Applying the syntax for a private_instantiation_declaration to the above
allows us to write;

with Device_Driver;
private with Interfaces.C;

package Audio_Driver is
   package Audio_Device_Driver is new private Device_Driver (others => private);

   -- These renamed subprograms are the only visible operations
   procedure Activate renames Audio_Device_Driver.Driver.Activate;
   function Is_Operational return Boolean renames Audio_Device_Driver.Driver.Is_Operational;

   --  Note Audio_Device is more private than if we had declared it as a private type.
   --  You cannot even declare an Audio Device, or call Power_On, or Playing_Music directly
   --  But you can call Audio_Device_Driver.Activate, or Audio_Device_Driver.Is_Operational
   --  to do the same thing.
   -- Note you cannot call Configure because the type associated with one of the formal parameters
   -- of that call (Audio_Settings) is not visible.

private

   use Interfaces;
   type Audio_Device is
      record
         Handle : C.int;
         Big_Ugly_Structure : ...
      end record;
   pragma Convention (C, Audio_Device);

   procedure Power_On (Device : Audio_Device);  -- Actual procedure
   function Playing_Music (Device : Audio_Device) return Boolean; -- Actual Function

   Muted : Boolean := False;  -- Actual Variable

   type Audio_Quality is (High, Medium, Low);
   Default_Codec : constant := 16#DEADBEEF#;
   type Audio_Settings is
      record
         Codec : C.unsigned_long := Default_Codec;
         Quality : Audio_Quality := High;
      end record;
   procedure Setup (Device : Audio_Device; Settings : Audio_Settings);
   pragma Convention (C, Audio_Settings);

   package Audio_Device_Driver is new Device_Driver
     (Device_Type => Audio_Device,  -- Actual Type
      Manufacturer => "Acme Corp",  -- Actual Constant
      Model => "SoundWhomper Mark IV", -- Actual Constant
      Disabled => Muted, -- Actual Variable
      Activate_Device => Power_On, -- Actual procedure
      Device_Is_Operational => Playing_Music, -- Actual function
      Configuration_Settings => Audio_Settings, -- Actual procedure
      Configure_Device => Setup);  -- Actual type

end Audio_Driver;

This dramatically simplifies the visible part of the package specification.

Now suppose, we want to allow clients to access the mute variable which is
supplied as an actual.

The visible part of the package specification would then look like;

package Audio_Driver is

   Muted : Boolean := False;  -- Actual Variable

   package Audio_Device_Driver is new private Device_Driver
            (Disabled => Muted, others => private);
...

Clients can mute the sound simply by modifying the Muted variable.
This seems to better separate the actual variable from the instantiated abstraction.

Now suppose we want to support multiple configurations, and allow clients
to be able to use of the Configure call.
This can be accomplished by modifying the visible part of the package
to look like;

package Audio_Driver is

   Muted : Boolean := False;

   type Audio_Settings is private;

   package Audio_Device_Driver is new private Device_Driver
            (Disabled => Muted,
             Configuration_Settings => Audio_Settings,
             others => private);
...


A second example of using deferred actuals would be helpful.
Suppose we have a set of container packages that implement a queue abstraction.
The root package defines the interface to a queue, and child packages create various
implementations of the interface

generic
   type Element_Type is private;
   pragma Preelaborable_Initialization (Element_Type);
   type Element_Index_Type is range <>;
   type Element_Array_Type is array (Element_Index_Type range <>) of Element_Type;

package Queues is
   pragma Pure;

   type Queue_Interface is limited interface;

   --  Get and Put a single element from/to the queue
   procedure Get (Container : in out Queue_Interface; Item : out Element_Type) is abstract;
   procedure Put (Container  : in out Queue_Interface; Item : Element_Type) is abstract;

   --  Get and Put multiple elements from/to the queue
   procedure Get (Container : in out Queue_Interface;
                  Item : out Element_Array_Type;
                  Last : out Element_Index_Type) is abstract;

   procedure Put (Container  : in out Queue_Interface; Item : Element_Array_Type) is abstract;

   type Queue_Type (Capacity : Natural) is abstract new Queue_Interface with null record;

   type Queue_Class_Access is access all Queue_Interface'Class;

end Queues;

Suppose that there exist three implementations of this interface.
  1) A Bounded queue
  2) A Queue of bounded queues that presents an abstraction of a
     queue that presents an array of Bounded queues as a single queue


generic
   type Queue_Array_Type is
     array (Natural range <>) of Queue_Class_Access;
   Queues : Queue_Array_Type;
package Queues.Multi is
...

   3) A protected queue that wraps a lower level queue into a protected object
      to allow save concurrent access

generic

   type Queue_Implementation is new Queue_Type with private;
   pragma Preelaborable_Initialization (Queue_Implementation);

package Queues.Concurrent is
   pragma Pure;

   protected type Queue (Capacity : Natural) is new Queue_Interface with
      overriding procedure Get (Item : out Element_Type);
      overriding procedure Get (Item : out Element_Array_Type; Last : out Element_Index_Type);
      overriding procedure Put (Item : Element_Type);
      overriding procedure Put (Item : Element_Array_Type);
   private
      Data          : Queue_Implementation (Capacity);
   end Queue;
   pragma Preelaborable_Initialization (Queue);
end Queues.Concurrent;

Now suppose we want to create a protected queue of bounded queues, but for this
abstraction we are only interested in Get and Put calls that operate on a single
element. The Get and Put calls that operate on an array of elements are not
going to be used. Further, we want to ensure that clients of this abstraction do
not use these Get and Put calls, because someday we might want to replace the
use of these containers with a simpler set of abstractions that do not have
these calls. The proposed syntax allows us to write:


private with Queues.Bounded; -- Simple bounded queue
private with Queues.Multi;   -- A "medium-level" generic queue-of-bounded-queues container
with Queues.Concurrent;      -- A "high-level" protected queue of bounded queues container

package Pkg is

   Maximum_Capacity : constant := 300;  -- Max. no. of elements in the Q

   type T is tagged private;

   function Create return T;
   pragma Preelaborable_Initialization (T);

   -- Declare a private instantiation of the interface. Since the array
   -- type actuals are being deferred to the private part, clients can not
   -- use primitives that involve these types, because they are not visible types.
   package I is new private Queues
     (Element_Type => T, others  => private);

   -- The protected queue of bounded queues abstraction
   package I4 is new private I.Concurrent
     (Queue_Implementation => private);


private

   type T is tagged
      record
         ...
      end record;

   --  Deferred actuals not accessible from outside this package
   type T_Index_Type is new Natural;
   type T_Array_Type is array (T_Index_Type range <>) of T;

   --  Instantiate interface for a queue
   package I is new Queues
     (Element_Type => T,
      Element_Index_Type => T_Index_Type,
      Element_Array_Type => T_Array_Type);

   --  Instantiate the "low-level" bounded queue implementation capable
   --  of storing elements of type T
   package I2 is new I.Bounded;

   --  Declare some queues to be used in instantiating a queue of queues
   Q1 : aliased I2.Queue (Capacity => 100);
   Q2 : aliased I2.Queue (Capacity => Maximum_Capacity - Q1.Capacity);

   --  Declare types needed to instantiate queue of queues generic
   type Queue_Array is array (Natural range <>)
     of access I.Queue_Interface'Class;
   Queues : constant Queue_Array
     := Queue_Array'(1 => Q1'Access, 2 => Q2'Access);

   --  Instantiate a queue of queues generic
   package I3 is new I.Multi
     (Queue_Array_Type => Queue_Array, Queues => Queues);

   --  Now instantiate a protected queue of queues.
   package I4 is new I.Concurrent (Queue_Implementation => I3.Queue);

end Pkg;



!Example

Now lets look at how the proposed syntax could be applied to the
examples in the problem section of this AI.

Here is the generic signature example:

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;
   function Size(Of_Set : Set) return Natural is <>;
   function Intersection(Left, Right : Set) return Set is <>;
   function Empty return Set is <>;
   function Unit_Set(With_Item : Element) return Set is <>;
   function Nth_Element(Of_Set : Set) return Element is <>;
   package Signature is new private Set_Signature (Elem, Set);
private
   type Set is record ... end record;
   package Signature is new Set_Signature(Elem, Set);
end Hashed_Sets;

In this case, it appears that Hashed_Sets is itself a general purpose
container abstraction meant to be used on its own, and the above
would be an appropriate package specification.

Suppose however, that this package were intended to be only
used to create higher level abstractions by using the Signature
Instantiation as a package formal to instantiate a higher level
generic package. In a sense this could be considered as a type of
abstract package that is not to be used on its own.
In this case, we would like to be able to hide more details in the
private part, and ensure that only the Signature instantiation is
exported from this generic package. Using the proposed syntax,
this allows us to write:

generic
   type Elem is private;
   with function Hash (El : Elem) return Integer;
package Hashed_Sets is

   type Set is private;
   package Signature is new private Set_Signature (Elem, Set, others => private);

private
   type Set is record ... end record;
   function Union (Left, Right : Set) return Set;
   function Size (Of_Set : Set) return Natural is <>;
   function Intersection (Left, Right : Set) return Set is <>;
   function Empty return Set is <>;
   function Unit_Set (With_Item : Element) return Set is <>;
   function Nth_Element (Of_Set : Set) return Element is <>;
   package Signature is new Set_Signature (Elem, Set);
end Hashed_Sets;


Here is an example where we want to instantiation a container:

package Expressions is
   type Expr_Ref is private;
   package Expr_Sequences is new private Sequences(Expr_Ref);
   function Operands(Expr : Expr_Ref) return access Expr_Sequences.Sequence;
   ...
private
   type Expression; -- completion deferred to body
   type Expr_Ref is access Expression;
   package Expr_Sequences is new Sequences(Expr_Ref);
end Expressions;

Note that being able to access the instantation in the visible part
with a partial view provides a simple easy to understand solution
without having to introduce incomplete types, derived types, or even named
access types.

This proposal appears to have the capabilities of the other proposals of this
AI, (AI05-0074-1, AI05-0074-2, and AI05-0074-3), plus additional capabilities
although at first glance it would appear that AI05-0074-2 solves a problem that
this proposal does not.

The example sited is;

package Constructs is
   type Root_Construct_Handle is abstract tagged private;
   ...
   generic
      type Data_Part is private;
   package Handles is
      type Construct_Handle is new Root_Construct_Handle with private;
      type RO_Access is access constant Data_Part;
      type RW_Access is access all Data_Part;
      function Get_RO_Access(Handle : Construct_Handle) return RO_Access;
      function Get_RW_Access(Handle : Construct_Handle) return RW_Access;
   private
      type Construct_Handle is new Root_Construct_Handle with ...
      -- ERROR: Parent type of record extension
      -- must be completely defined. end Handles;
private
   type Root_Construct_Record; -- completed in pkg body
   type Root_Construct_Access is access all Root_Construct_Record;
   type Root_Construct_Handle is abstract tagged
      record
         Construct : Root_Construct_Access;
         ...
      end record;
end Constructs;

However, a reasonable solution to this example seems to already exist
with the current version of the Ada standard. By moving the first
set of declarations into a nested package, the nested generic is able
to exist without the need for declaring an "end private".

package Constructs is

   package Sub is
      type Root_Construct_Handle is abstract tagged private;
      ---  ...
   private
      type Root_Construct_Record;
      --  completed in pkg body
      type Root_Construct_Access is access all Root_Construct_Record;
      type Root_Construct_Handle is abstract tagged
         record
            Construct : Root_Construct_Access;
           --  ...
         end record;
   end Sub;

   use Sub;
   generic
      type Data_Part is private;
   package Handles is
      type Construct_Handle is new Root_Construct_Handle with private;
      type RO_Access is access constant Data_Part;
      type RW_Access is access all Data_Part;
      function Get_RO_Access (Handle : Construct_Handle) return RO_Access;
      function Get_RW_Access (Handle : Construct_Handle) return RW_Access;
   private
      type Construct_Handle is new Root_Construct_Handle with
         record
            X : Integer;
         end record;
   end Handles;
end Constructs;

It might be worth considering how the various proposals compare
with regard to solving the seven problems mentioned in the discussion
of this proposal.

Problem 1: Using Private types as actuals to a generic

AI05-0074-1 - Solves
AI05-0074-2 - Solves
AI05-0074-3 - Solves
AI05-0074-4 - Solves

Problem 2: Exporting a variable of a private type

AI05-0074-1 - Does not solve
AI05-0074-2 - Solves
AI05-0074-3 - Does not solve
AI05-0074-4 - Solves

Problem 3: Exporting a derived untagged private type

AI05-0074-1 - Does not solve
AI05-0074-2 - Solves
AI05-0074-3 - Does not solve
AI05-0074-4 - Solves

Problem 4: Exporting derived type of instantiated package

AI05-0074-1 - Does not solve
AI05-0074-2 - Solves
AI05-0074-3 - Does not solve
AI05-0074-4 - Solves

Problem 5: Types can have components that access instantiations using the type

AI05-0074-1 - Partly solves but does not see into visible instantiations of instantiated generic
              because only a limited view is seen of the instantiated package.
AI05-0074-2 - Partly solves in a more awkward manner using incomplete types and type derivations.
              Does not work for protected types, because you cannot derive from a protected type.
AI05-0074-3 - Does not solve
AU05-0074-4 - Solves

Problem 6: Deferring declaration of actuals to the private part for an exported instantiation

AI05-0074-1 - Does not solve
AI05-0074-2 - Does not solve
AI05-0074-3 - Does not solve
AI05-0074-4 - Solves

Problem 7: Limiting access to exported instantiation

AI05-0074-1 - Does not solve
AI05-0074-2 - Does not solve
AI05-0074-3 - Does not solve
AI05-0074-4 - Solves

!ACATS test

ACATS B and C-Test(s) are necessary.

****************************************************************

From: Steve Baird
Sent: Wednesday, January 7, 2009  1:25 PM

Steve Wrote:
 > P.S. Do you think there is any benefit in allowing the May_Be_Partial  > pragma (or whatever name we might settle on) to apply to a  > formal array type?
 >
 >    type T is private;
 >    type T_Vector is array (Positive range <>) of T;
 >
 >    package I is new G (T, T_Vector);
 >   private
 >    type T is ... ;
 >
 > Or is this just a solution looking for a problem?

Brad Moore replied:

That's a good point. I think that is needed. That raises another question. If
May_Be_Partial is applied to a private type, is it implicitly also applied to
formal array of that type, or does it need to be explicit?

I would think, this the wording should say that this can be implicit, but
explicitly is allowed also, as that may help document that fact that it may be a
partial type.

eg. From my example below....

generic
    type Element_Type is private;
    pragma Preelaborable_Initialization (Element_Type);
    pragma May_Be_Partial (Element_Type);

    type Element_Index_Type is range <>;

    type Element_Array_Type is array (Element_Index_Type range <>) of Element_Type;
    pragma May_Be_Partial (Element_Array_Type); -- Can this pragma be Implicitly declared here?

package Queues is ...



I think I have a pretty good example of how this might be beneficial.
See below.


I have a generic that can be applied to any object that one might want to sell.

with Ada.Calendar; use Ada.Calendar;
generic
    type Sellable_Type is tagged private;
    pragma May_Be_Partial (Sellable_Type);
    pragma Preelaborable_Initialization (Sellable_Type); package Sellable_Item is
    type Dollars is delta 0.01 digits 10;
    type Condition is (Poor, Fair, Good, Excellent);

    type Valued_Item is new Sellable_Type with private;
    pragma Preelaborable_Initialization (Valued_Item);

    function Buying_Price (Item : Valued_Item) return Dollars;
    function Estimated_Value (Item : Valued_Item) return Dollars;
    function Selling_Price (Item : Valued_Item) return Dollars;

    function Create
      (Item : Sellable_Type;
       Purchase_Cost : Dollars;
       Asking_Price : Dollars;
       Purchase_Date : Time;
       Original_Condition : Condition;
       Current_Condition : Condition) return Valued_Item;

private

    type Valued_Item is new Sellable_Type with
       record
          Purchase_Price : Dollars;
          Purchase_Year : Integer;
          Purchase_Condition : Condition;
          Asking_Price : Dollars;
          Current_Condition : Condition;
       end record;

end Sellable_Item;

package body Sellable_Item is

    function Buying_Price (Item : Valued_Item) return Dollars is
    begin
       return Item.Purchase_Price;
    end Buying_Price;

    function Create
      (Item : Sellable_Type;
       Purchase_Cost : Dollars;
       Asking_Price : Dollars;
       Purchase_Date : Time;
       Original_Condition : Condition;
       Current_Condition : Condition) return Valued_Item
    is
    begin
       return Valued_Item'
           (Item  with
            Purchase_Price => Purchase_Cost,
            Asking_Price => Asking_Price,
            Purchase_Year => Year (Purchase_Date),
            Purchase_Condition => Original_Condition,
            Current_Condition => Current_Condition);
    end Create;

    function Estimated_Value (Item : Valued_Item) return Dollars is
       pragma Unreferenced (Item);
    begin
       return 0.00;  -- Calculated value from purchase date, price, depreciation, currency value changes, market conditions, etc.
    end Estimated_Value;

    function Selling_Price (Item : Valued_Item) return Dollars is
    begin
       return Item.Asking_Price;
    end Selling_Price;

end Sellable_Item;

Now I want to use this package to sell paintings, and the goal is to be able to
add collections of paintings to an Art Gallery (which is implemented as a
bounded buffer in this case)

with Sellable_Item;
with Queues.Bounded;

package Art_Sale is

    type Painting is tagged private;
    pragma Preelaborable_Initialization (Painting);

    procedure Create
      (Artist : String;
       Title : String;
       Item : out Painting);

    function Artist (Item : Painting) return String;
    function Title (Item : Painting) return String;

    package Sellable_Art is new private Sellable_Item (Painting);

    type Masterpiece is new Sellable_Art.Valued_Item with private;
    function May_Have_Been_Stolen (Item : Masterpiece) return Boolean;

    type Collection is array (Integer range <>) of Masterpiece;

    package Exhibit is new private Queues -- Instantiate Interface
      (Element_Type => Masterpiece,
       Element_Index_Type => Natural,
       Element_Array_Type => Collection);

    package Art_Gallery is new private Exhibit.Bounded;  -- Can store collections of paintings into a buffer

private

    type Painting is tagged record
       Artist_Name : String (1 .. 10);
       Work_Title : String (1 .. 10);
    end record;

    package Sellable_Art is new Sellable_Item (Painting);

    type Masterpiece is new Sellable_Art.Valued_Item with
       record
          Appraised_Value : Sellable_Art.Dollars;
       end record;

    package Exhibit is new Queues
       (Element_Type => Masterpiece,
        Element_Index_Type => Natural,
        Element_Array_Type => Collection);

    package Art_Gallery is new Exhibit.Bounded;

end Art_Sale;

package body Art_Sale is
    function Artist (Item : Painting) return String is
    begin
       return Item.Artist_Name;
    end Artist;

    procedure Create
      (Artist : String;
       Title : String;
       Item : out Painting) is
    begin
       Item := Painting'(Artist, Title);
    end Create;

    function May_Have_Been_Stolen (Item : Masterpiece) return Boolean is
       function Reported_Stolen (Artist, Title : String) return Boolean is
       begin
          return False; -- Check public data bases
       end Reported_Stolen;
       use type Sellable_Art.Dollars;
    begin
       if Reported_Stolen (Item.Artist, Item.Title) or Item.Selling_Price < Item.Appraised_Value * 0.5 then
          return True;
       else
          return False;
       end if;
    end May_Have_Been_Stolen;

    function Title (Item : Painting) return String is
    begin
       return Item.Work_Title;
    end Title;

end Art_Sale;

generic
    type Element_Type is private;
    pragma Preelaborable_Initialization (Element_Type);
    pragma May_Be_Partial (Element_Type);

    type Element_Index_Type is range <>;

    type Element_Array_Type is array (Element_Index_Type range <>) of Element_Type;
    pragma May_Be_Partial (Element_Array_Type); -- Can be Implicitly declared?

package Queues is
    pragma Pure;

    type Queue_Interface is limited interface;

    --  Get and Put a single element from/to the queue
    procedure Get (Container : in out Queue_Interface; Item : out Element_Type) is abstract;
    procedure Put (Container  : in out Queue_Interface; Item : Element_Type) is abstract;

    --  Get and Put multiple elements from/to the queue
    procedure Get (Container : in out Queue_Interface;
                         Item : out Element_Array_Type;
                         Last : out Element_Index_Type) is abstract;

    procedure Put (Container  : in out Queue_Interface; Item : Element_Array_Type) is abstract;

    type Queue_Type (Capacity : Natural) is abstract new Queue_Interface with null record;

    type Queue_Class_Access is access all Queue_Interface'Class;

end Queues;

generic
package Queues.Bounded is

    pragma Pure;

    type Queue_Data (Capacity : Natural) is private;
    pragma Preelaborable_Initialization (Queue_Data);

    type Queue (Capacity : Natural) is new Queue_Type (Capacity) with
       record
          Data : Queue_Data (Capacity);
       end record;

    overriding procedure Get (Container : in out Queue; Item : out Element_Type);
    overriding procedure Get (Container : in out Queue;
                                        Item : out Element_Array_Type;
                                        Last : out Element_Index_Type);

    overriding procedure Put (Container : in out Queue; Item : Element_Type);
    overriding procedure Put (Container : in out Queue; Item : Element_Array_Type);

private

    type Data_Array_Type is array (Natural range <>) of Element_Type;

    type Queue_Data (Capacity : Natural)
      is
       record
          Items      : Data_Array_Type (1 .. Capacity);
          Read_Pos  : Natural := 1;
          Write_Pos : Natural := 1;
          Full : Boolean := False;
       end record;

end Queues.Bounded;

****************************************************************

From: Brad Moore
Sent: Sunday, February 15, 2009  4:05 PM

I have made significant changes to the proposal I have been working on for
AI05-0074. Thanks to Randy for providing good feedback, I have had a pretty
good email exchange with him on these ideas over that past month or so.

Randy will probably be somewhat surprised however, as what I have ended up
with has changed quite a bit since our last email exchange. My thoughts have
evolved considerably since I started on this, but I think I am finally at a
stable place and hopefully something worthy of consideration.

To summarize the changes and where I am at now;

1) I have done away with the need for a May_Be_Partial pragma with this
   proposal
2) There are no changes to the freezing rules, or the generic contract
   model.
3) There are no restrictions placed on the content of a generic package,
   Though there are restrictions on the use of the instance until the
   completion of the private instantiation.
4) I still have the ability to defer actuals to the private part
5) I have done away with a lot of other features that I had been toying
   with.  (No derivations of partial untagged types, no private objects)
6) I have also realized that there isn't sufficient need to be able to
   instantiate generics with a type that has an incomplete view.
   One workaround is to make the type a private type and use a
   private_instantiation_declaration.

    -- Private_Instantiation_Declaration eg. package Foo is private new
       Ada.Containers.Doubly_Linked_Lists
         (Element_Type => T, Others => Private);
    --  "=" has been deferred to the private part

However, actuals for formal types or formal packages must be explicitly
specified and cannot be deferred. This eliminates cases that I found to be
problematic.

A private_instantiation_declaration declares two views of an instance.
A partial view of an instance, and a full view of an instance.
The partial view applies to the immediately enclosing declarative region,
while the full view applies to outside program units, and is equivalent to
the view provided by the generic_instantiation declaration in the private
part, which is placed after the actuals have been defined.

Semantically, a partial view of an instance is like a view of the text of
the generic template, without having made substitutions of actuals for
formals, and where the mappings from actuals to formals has not yet been
resolved.

In my travels, I have also ran into some problems with existing workarounds,
which are addressed by this proposal, and I have captured these in the
attachment.

Looking forward to seeing everyone in Tallahassee

[This was version /01 of the AI - ED.]

****************************************************************

From: Brad Moore
Sent: Monday, February 16, 2009  10:33 PM

Sorry, this is a minor update to the update. It corrects some typos and
deletes some residual wording left over from an earlier version of the
write up. I thought I had caught them all, but noticed today that I missed
a few.

[This was version /02 of the AI - ED.]

****************************************************************

Questions? Ask the ACAA Technical Agent