CVS difference for ais/ai-60217.txt

Differences between 1.2 and version 1.3
Log of other versions for file 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