CVS difference for ais/ai-60217.txt
--- ais/ai-60217.txt 2003/05/24 00:51:43 1.2
+++ ais/ai-60217.txt 2003/06/17 21:34:34 1.3
@@ -1,48 +1,275 @@
-!standard 03.10.01 (02) 03-03-03 AI95-00217-07/00
+!standard 03.10.01 (02) 03-03-04 AI95-00217-07/01
+!standard 03.10.01 (03)
+!standard 03.10.01 (11)
+!standard 08.03.00 (19)
!class amendment 03-03-03
!status work item 03-03-03
!status received 03-03-03
!priority Medium
!difficulty Hard
-!subject Child type stubs
+!subject Incomplete type completed in a child
!summary
-A new kind of incomplete type is proposed.
+A new form of incomplete type declaration is provided for
+specifying that a type is to be completed in a child or nested
+package. This enables a set of mutually dependent type definitions
+to cross packages that are part of a package hierarchy.
!problem
-Ada allows mutually recursive types to be declared only if they are all
-declared within the same library unit. This can force all of the major data
-structures of a program into a single library unit, which is clearly
-undesirable in some situations.
-
-The goal of the proposed feature is to allow mutual recursion among type
-declared in separate packages (types containing (pointers to) each other as
-components, and primitive operations with (pointers to) each other as
-parameters), and to do this in a way that doesn't place any undue restrictions
-on the programmer.
-
-For mutually recursive types, it is valuable if subprogram parameters may be of
-the type itself, rather than only an access to the type. However, for most
-types, it may be necessary to see the full definition to know how parameters of
-the type are passed. However, because tagged types are always passed by
-reference, there is no implementation difficulty in allowing them to be used as
-parameters even when the full definition of the type is not available. Hence,
-it makes sense to relax the rule for using incomplete types that are known to
-be tagged, to allow them as formal and actual parameters, since from a code
-generation point of view they are essentially equivalent to access parameters.
+Ada 95 does not allow two package specs to depend on each other. This
+can cause problems when creating Ada packages to use in interfacing with code
+written in languages like Java. In Java, there are no restrictions against
+mutually dependent class definitinos. When expressed in Ada, this means
+that a package may define a type which is used in a second package's spec,
+while also making use of a type defined in that package spec. This is
+clearly not allowed due to restrictions against cyclic semantic dependences.
+Cyclic semantic dependences cannot generally be allowed in Ada because of
+the order of elaboration requirements.
+
+This problem also can occur when organizing large object-oriented systems
+solely in Ada 95. The "solution" is to place all of the types in a single
+package. However, the rules for defining primitive operations of a type
+require that most of the operations of the type also must be declared in
+the package. This leads to gigantic packages. An alternative solution is
+to add additional indirection into the data structures. This adds complexity
+as well as space and time costs at runtime.
!proposal
-Tucker's "type C.T;".
+(See wording.)
!wording
-!discussion
+Change paragraphs 3.10.1(2,3) as follows ("{}" are additions,
+"[]" are deletions, except in the syntax part):
+
+ incomplete_type_declaration ::=
+ TYPE [package_identifier.]defining_identifier[discriminant_part]
+ [is tagged];
+
+ An incomplete_type_declaration requires a completion, which shall be
+ a full_type_declaration {, a private_type_declaration, or a
+ private_extension_declaration}. {If a package_identifier
+ is present in the declaration, the completion shall occur immediately
+ within the visible part of a package with this identifier,
+ which shall be declared later and immediately within the innermost
+ enclosing declarative region. Otherwise, if}[If] the
+ incomplete_type_declaration occurs immediately within ...
+ < rest remains the same >.
+
+Add the following sentences to the end of paragraph 3.10.1(11):
+
+ If a package_identifier is present in the declaration, the
+ incomplete type is declared immediately within the declarative
+ region of the named package. Otherwise, the incomplete type is
+ declared immediately within the innermost enclosing declarative region.
+
+Change 8.3(19) as follows:
+
+ If the completion of a declaration is a declaration, then [within
+ the scope of] {in places where} the completion {is visible}, the
+ first declaration [is] {, and any declarations it completes, are}
+ hidden from all visibility. Similarly, a discriminant_specification
+ or parameter_specification is hidden [within the scope of]
+ {in places where} a corresponding discriminant_specification
+ or parameter_specification of a corresponding completion, or
+ of a corresponding accept_statement {is visible}.
!example
+(a) Here is the classic case of mutual dependence, where an employee
+belongs to a particular department, and a department has a manager who
+is an employee. (We assume the use of tagged types here to illustrate the
+use of tagged incomplete types.)
+
+-----------------
+
+ package Office is
+ type Departments.Department is tagged;
+ type Dept_Ptr is access all Department'Class;
+ end Office;
+
+ package Office.Employees is
+ type Employee is tagged private;
+ type Emp_Ptr is access all Employee'CLass;
+ procedure Assign_Employee(E : in out Employee;
+ D : in out Departments.Department);
+ ...
+ function Current_Department(D : in Employee) return Dept_Ptr;
+ end Office.Employees;
+
+ with Office.Employees;
+ package Office.Departments is
+ type Department is tagged private;
+ subtype Dept_Ptr is Office.Dept_Ptr;
+ procedure Choose_Manager(D : in out Department;
+ Manager : in out Employees.Employee);
+ ...
+ end Office.Departments;
+
+--------------
+
+(b) If it is desirable that Employees and Departments be
+top-level library packages, the following renames can be provided:
+
+ with Office.Employees;
+ package Employees renames Office.Employees;
+
+ with Office.Departments;
+ package Departments renames Office.Departments;
+
+----------
+
+(c) Alternatively, there is really no need for Employees to
+be a child in the above example, so it can be defined
+directly as package "Employees" rather than
+as package "Office.Employees," eliminating the need
+for the first renaming. In this case, package "Office"
+might better be called something else, since it no longer
+encapsulates the entire "office" abstraction.
+E.g., it might be called simply "Forward":
+
+ package Forward is
+ -- "Forward" declarations of types that complete a cycle
+ type Departments.Department is tagged;
+ type Dept_Ptr is access all Department'Class;
+ ... -- and possibly other types needed to break a cycle
+ end Forward;
+
+ with Forward; use Forward;
+ package Employees is
+ type Employee is tagged private;
+ type Emp_Ptr is access all Employee'CLass;
+ procedure Assign_Employee(E : in out Employee;
+ D : in out Departments.Department);
+ ...
+ function Current_Department(D : in Employee) return Dept_Ptr;
+ end Employees;
+
+ with Employees;
+ package Forward.Departments is
+ type Department is tagged private;
+ subtype Dept_Ptr is Forward.Dept_Ptr;
+ procedure Choose_Manager(D : in out Department;
+ Manager : in out Employees.Employee);
+ ...
+ end Forward.Departments;
+
+ with Forward.Departments;
+ package Departments renames Forward.Departments;
+
+-------------------
+(d) One option not fully analyzed would be to allow the
+incomplete type to be completed by a type within
+a package renaming. This might require somewhat different
+wording changes, but this is how the above example would look.
+Note that now the packages are both defined as top-level
+library packages, and the only child unit is a renaming:
+
+ package Forward is
+ -- "Forward" declarations of types that complete a cycle
+ type Departments.Department is tagged;
+ type Dept_Ptr is access all Department'Class;
+ ... -- and possibly other types needed to break a cycle
+ end Forward;
+
+ with Forward; use Forward;
+ package Employees is
+ type Employee is tagged private;
+ type Emp_Ptr is access all Employee'CLass;
+ procedure Assign_Employee(E : in out Employee;
+ D : in out Departments.Department);
+ ...
+ function Current_Department(D : in Employee) return Dept_Ptr;
+ end Employees;
+
+ with Forward;
+ with Employees;
+ package Departments is
+ type Department is tagged private;
+ subtype Dept_Ptr is Forward.Dept_Ptr;
+ procedure Choose_Manager(D : in out Department;
+ Manager : in out Employees.Employee);
+ ...
+ end Departments;
+
+ with Departments;
+ package Forward.Departments renames Departments;
+ -- complete the type via a renaming (possible option)
+
+
+!discussion
+
+This proposal attempts to address the need to have types that
+are mutually dependent which are not all defined in the same
+library package. The approach is built upon the idea that
+any group of types that are mutually dependent are necessarily
+part of a single logical abstraction, and hence will often
+be declared as part of a package hierarchy. We take advantage
+of this by placing the incomplete type declaration in the
+root package of the abstraction, and then the types that are mutually
+dependent can be declared in this same package, or in its
+children.
+
+The proposed syntax is intended to be analogous to the syntax
+used for declaring child units, and in fact was discussed
+during the Ada 9X design process as a natural extension
+of deferred incomplete types. The problem in the Ada 9X
+process was we only considered allowing the declaration in
+the private part of the parent. That, unfortunately, doesn't
+solve the mutually dependent type problem. By allowing
+this generalized incomplete type declaration in the visible
+part of the parent, we have completed the process of allowing
+a large abstraction to be spread across multiple packages
+in a hierarchy.
+
+In fact, the proposal is not restricted to packages in a hierarchy,
+though that is one anticipated style of usage. Only the
+package that breaks the cycle need be declared as a child.
+All the other packages can be declared as top-level library units,
+as illustrated in the first "package Forward" example above (example (c)).
+
+Note that this proposal allows the completing type to be
+defined in an instantiation. The second "package Forward" example
+(example (d)) illustrates a further option, where we would allow the
+type to be "completed" in a renaming. Although this option
+has not been fully investigated, it has the interesting
+effect of allowing all the package declarations to be
+top-level, and only the renaming is a child. This option
+might resolve some of the concerns about being forced to
+declare one or more packages as children.
+
+The wording change to 8.3(19) deserves some extra discussion. The change
+from "within the scope" to "places where visible" seems necessary for
+any of our proposals, to avoid the "ripple" effect where an indirect "with"
+dependence can have significant effects on a unit outside the
+scope of the "with" clause.
+
+The original "within scope" wording would pull completions
+into all semantic dependents of the completing package, since the
+scope of a library item extends to all its dependents, including
+those units that do not have "with" visibility on the _item. But
+we have agreed in past discussions that we want the completing
+package (or a rename thereof) to be visible, not just somewhere
+within scope, if we are going to consider the type "completed."
+The new wording of the paragraph is intended to have no effect
+on existing code.
+
+One note about the syntax, to address Randy's concern. Adding the
+optional "[package_identifer.]" to the syntax could be treated by the
+parser roughly in the same way as the optional "[parent_unit_name.]"
+is treated in section 6.1 for defining_unit_name. You could allow
+this prefix on any type declaration, and then have a semantic
+rule that makes sure it is only used for incomplete type
+declarations.
+
+To summarize, this proposal is intended to involve the smallest change
+to the RM wording and to most implementations, and with the use of one
+package renaming as illustrated in the "package Forward" examples
+((c) and (d)), it can accommodate use of the feature for packages that
+are not all part of a single package hierarchy.
!ACATS test
!appendix
@@ -51,7 +278,17 @@
AI-217-05.
**************************************************************
+
+From: Tucker Taft
+Sent: Thursday, February 13, 2003 2:48 PM
-[Editor's note: Mail about this proposal is not posted yet. Sorry.]
+I was tasked with writing up the "type C.T;" proposal. Here it
+is. [Editor's note: This is version /01 of the AI.]
+One interesting option presented itself as I was working on it.
+If we permit these incomplete types to be completed by a renaming
+of a package, then the packages participating in the cycle can
+all be declared as top-level library units. See example (d) in
+the AI for how this might look. I think this paradigm might
+alleviate the concern about being forced to use child units.
**************************************************************
Questions? Ask the ACAA Technical Agent