CVS difference for ai05s/ai05-0074-2.txt

Differences between 1.1 and version 1.2
Log of other versions for file ai05s/ai05-0074-2.txt

--- ai05s/ai05-0074-2.txt	2008/01/19 07:25:32	1.1
+++ ai05s/ai05-0074-2.txt	2008/08/01 04:26:14	1.2
@@ -1,14 +1,24 @@
-!standard 7.1(3)                                      08-01-18    AI05-0074-2/00
+!standard 7.1(3)                                      08-07-20    AI05-0074-2/01
+!standard 7.1(6/2)
+!standard 7.3(4)
+!standard 7.4(3)
+!standard 8.2(2)
+!standard 8.2(8)
+!standard 8.2(9)
 !class Amendment 08-01-18
 !status work item 08-01-18
 !status received 07-09-27
 !priority Medium
 !difficulty Hard
-!subject The "End Private" part
+!subject Allowing an explicit "end private;" in a package spec
 
 !summary
 
-(See proposal.)
+Allow "end private;" in a package spec to end the private part, and
+allow additional visible declarations (such as generic instantiations)
+to be provided thereafter. These post-private declarations may take
+advantage of the fact that the private views and deferred constants of
+the package have been completed.
 
 !problem
 
@@ -100,24 +110,224 @@
 
 !proposal
 
-Introduce an "end private" part in package specifications.
-
-This idea slices, dices, and cures body odor, while not causing a single problem.
-It is impossible to imagine why this flawless idea was never conceived of before.
+We propose to augment the syntax for package specs so that the end of
+the private part may be specified (with "end private;") and thereafter
+additional visible declarations may be provided. In the "post-private"
+visible part, no new private views nor deferred constants may be
+declared, as there would be no place to complete them. 
+
+When there is an "end private;" we might recommend that the declarations
+in the private part be indented.  For example:
+
+   package Abc is
+       type T is private;
+       Null_T : constant T;
+       
+     private
+         type T is new Integer;
+         Null_T : constant T := 0;
+     end private;
+     
+       package Lists_Of_T is new Generic_Lists(T);
+       type T_List is new Lists_Of_T.List;
+       
+    end ABC;
+    
+Allowing visible declarations after the private part allows generic
+instantiations and other constructs that freeze a private type (such as
+record extensions or variable declarations), to appear within the same
+package spec that defines the private type.
+
+The post-private visible part has no visibility on the private part. In
+that way it is analogous to the visible part of a child package.
+However, it can rely on the fact that all private views and deferred
+constants have been completed.  We do not allow multiple "private ...
+end private;" parts because then it would not be clear in which one a
+given private view or deferred constant is completed, without violating
+privacy.
 
 !wording
 
-[The proposal is impossible to object to until we get this wording. Then the
-organic material hits the automatic ventilating device. ;-)]
+Replace 7.1(3) with the following:
 
+  package_specification ::= 
+     package defining_program_unit_name is
+        {basic_declarative_item}
+      [private
+         {basic_declarative_item}
+      [end private;
+        {basic_declarative_item}]]
+     end [[parent_unit_name.]identifier]
+     
+Modify 7.1(6/2) as follows:
+
+   The first list of basic_declarative_items {and optional third list of
+   basic_declarative items} of a package_specification of a package
+   other than a generic formal package {comprise what} is called the
+   visible part of the package. [Redundant: The optional list of
+   basic_declarative_items [after] {following} the reserved word private
+   (of any package_specification) is called the private part of the
+   package. If the reserved word private does not appear, the package
+   has an implicit empty private part.] Each list of basic_declarative_
+   items of a package_specification forms a declaration list of the
+   package.
+   
+Modify 7.3(4) as follows:
+
+   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 first declaration list 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. [Redundant: 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.
+   
+     TBD: Is it OK to refer to the "first declaration list of the visible
+          part of a package"?  Does that work for generic packages, or
+          is the first declaration list the formal part?  Do we need to
+          say "first list of basic_declarative_items of the visible part
+          of the package"?  Same question applies for deferred constants
+          in 7.4(3).
+          
+Modify 7.4(3) as follows:
+
+   A deferred constant declaration that is completed by a full constant
+   declaration shall occur immediately within {the first declaration
+   list of} the visible part of a package_specification. For this case,
+   the following additional rules apply to the corresponding full
+   declaration: 
+   
+Add after 8.2(2):
+
+   * The immediate scope of a declaration in the private part of a package
+     or generic package does not include the optional third declaration
+     list of the package_specification, [Redundant: following the
+     reserved words END PRIVATE.]
+
+Modify 8.2(8) as follows:
+
+   * The visible part of a generic unit includes the generic_formal_part.
+     For a generic package, it also includes the first list {and optional
+     third list} of basic_declarative_items of the package_specification.
+     For a generic subprogram, it also includes the profile.
+   
+Modify 8.2(9) as follows:
+
+   * [Redundant: The visible part of a package, task unit, or protected unit
+     consists of declarations in the program unit's declaration other
+     than those following the reserved word PRIVATE, if any{, and
+     preceding the reserved words END PRIVATE, if any}; see 7.1 and 12.7
+     for packages, 9.1 for task units, and 9.4 for protected units.]
+
 !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.  
 
-Ada 2005 provides solutions to the problems given in the question, but they are not ideal.
+A third problem is best illustrated by an example:
 
-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):
+     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;
+     
+Here we want to define a nested generic package that exports a private
+extension of the private type Root_Construct_Handle. Everything is fine
+until we get to the private part of this nested generic, and we realize
+we need to give the full definition for the private extension, and we
+cannot, because that will freeze the private type.
+
+In all of these cases, moving the offending construct to after "end
+private;" would work as desired. A generic instantiation that takes the
+private type as a parameter, a variable of the private type, or a nested
+generic as illustrated above, would all be fine if declared after the
+completion of the private type. Note that none of these need actual
+visibility on the full definition of the type, they simply need the
+private type to have been completely defined, so that it is OK to freeze
+it.
+
+We have considered many alternatives in the past, such as "limited"
+instantiations of some sort, and Ada 2005 itself provides some
+"workarounds" that address the problems to some extent, involving child
+units or "limited with" (see below). But none of these alternatives
+address the core of the problem, which is a desire to have declarations
+in the same package spec where a private type is declared that currently
+are illegal because they freeze the private type.
+
+Allowing "end private;" has relatively straightforward semantics, with
+no new freezing rules or new kinds of instantiations. Other than the
+syntax change, the main significant change is the proposed 8.2 rule that
+the immediate scope of a declaration in the private part does *not*
+include the list of visible declarations, if any, that follow "end
+private;". This makes them very similar to the declarations in the
+visible part of a child unit.
+
+IMPLEMENTATION ISSUES
+
+Some implementors mentioned a concern that rarely do we "lose"
+visibility in a single construct, and that their implementations can't
+easily support that. One approach might be to treat the post-private
+visible part roughly like the visible part of a child, by starting from
+scratch and building up the visibility that corresponds to that which a
+(public) child unit sees, rather than trying to "remove" declarations
+from the existing visibility at the end of the private part.  
+
+Another possible approach might be to treat the private part roughly
+like a nested construct, where the visibility is "pushed" before the
+private part, and then "popped" afterward. Prior to popping the private
+part visibility, it would want to be "saved" so that when it is wanted
+again, such as in the package body, or in the private part of some
+child, it can be restored. This kind of "save" might be similar to 
+what is done with subunit "stubs."
+
+Ada 2005 WORKAROUNDS
+
+Here are some examples of how the problem could be addressed using
+existing Ada 2005 capabilities.
+
+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;
@@ -136,10 +346,11 @@
         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 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:
+The second problem can also be solved with child units, using the
+limited with:
 
     limited with Expressions.Sequences;
     package Expressions is
@@ -158,18 +369,99 @@
 
    package Expressions.Sequences is
        package Expr_Sequences is new Sequences(Expr_Ref);
-       type Sequences is Expr_Sequences.Sequence;
+       type Sequences 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.
+
+Here is the generic signature example, using "end private;":
+
+    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 private;
+      
+        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;
 
-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.
+        type Expr_Seq;  -- incomplete type
+        type Seq_Of_Expr is access Expr_Seq;
 
-[There needs to be a lot more discussion here.]
+        function Operands(Expr : Expr_Ref) return Seq_Of_Expr;
 
-!example
+        ...
 
+      private
+          type Expression;  -- completion deferred to body
+          type Expr_Ref is access Expression;
+      end private;
+      
+        package Expr_Sequences is new Sequences(Expr_Ref);
+        type Expr_Seq is new Expr_Sequences.Sequence;  
+          -- completion of incomplete type
+        
+   end Expressions;
 
+    
+Here is the nested generic with a private extension:
+    
+     package Constructs 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 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;
+       
+     end Constructs;
+         
+
 !ACATS test
 
 ACATS B and C-Test(s) are necessary.
@@ -3404,6 +3696,107 @@
 The previous sentence, about "completely defined", applies only to partial
 views declared in the first visible part, I presume.  Things declared (only) in
 the private part are irrelevant.
+
+****************************************************************
+
+From: Tucker Taft
+Date: Monday, July 21, 2008  3:09 PM
+
+I recently took 4, 4-hour train rides, and here is one of the products of
+having a bit too much time on my hands (it doesn't happen often!).
+[Ed. - this is version /01 of the AI.]
+
+****************************************************************
+
+From: Randy Brukardt
+Date: Thursday, July 31, 2008 11:22 PM
+
+> I recently took 4, 4-hour train rides, and here is one of the products 
+> of having a bit too much time on my hands (it doesn't happen often!).
+
+Please schedule some more train trips. Perhaps on the Trans-Siberian
+railroad. ;-)
+
+I took the time to read this entire proposal, and have some quibbles.
+(I haven't thought of any show-stoppers, but I haven't tried too hard to
+find them. That's Steve's job. ;-)
+
+The AI asks:
+> TBD: Is it OK to refer to the "first declaration list of the visible 
+> part of a package"?  Does that work for generic packages, or is the 
+> first declaration list the formal part?  Do we need to say "first list 
+> of basic_declarative_items of the visible part of the package"?  Same 
+> question applies for deferred constants in 7.4(3).
+
+"first list" and "third list" make me rather ill. I think that both of
+these parts need easy to remember names. Obviously, we have to talk about
+"first list" and "third list" when we define these names, but hopefully
+nowhere else. Calling them collectively the "visible part" is probably
+needed to avoid changing many other rules, but then they also need their
+own names. Perhaps "leading visible part" and "trailing visible part"?
+"primary visible part" and "seconday visible part"? Such a name also
+would get rid of the clunky "end private part" terminology that we've
+used for the lack of a decent name.
+
+Under "IMPLEMENTATION ISSUES", there is:
+
+> Another possible approach might be to treat the private part roughly 
+> like a nested construct, where the visibility is "pushed" before the 
+> private part, and then "popped" afterward.  Prior to popping the 
+> private part visibility, it would want to be "saved" so that when it 
+> is wanted again, such as in the package body, or in the private part 
+> of some child, it can be restored.  This kind of "save" might be 
+> similar to what is done with subunit "stubs."
+
+While I can't argue with the basic idea (it won't work in Janus/Ada,
+but that's not relevant), but I think the last sentence is bogus. Handling
+of a subunit "stub" means taking a snapshot of the state of the symboltable
+at the point of the stub and restoring it when needed. (Janus/Ada writes
+the entire snapshot to disk at this point, and loads it like a specification
+when processing the subunit.) That sort of approach would not work here,
+because it would drop the contents of the secondary visible part (ah, much
+better than "end private" part or "third declaration list"), which clearly
+wouldn't do. 
+
+Later in the discussion:
+
+> Allowing "end private;" has relatively straightforward semantics, with 
+> no new freezing rules or new kinds of instantiations. Other than the 
+> syntax change, the main significant change is the proposed 8.2 rule 
+> that the immediate scope of a declaration in the private part does 
+> *not* include the list of visible declarations, if any, that follow 
+> "end private;". This makes them very similar to the declarations in 
+> the visible part of a child unit.
+
+Humm, if we don't have any new freezing rules, then we have privacy leakage
+of freezing. Back in the day, Pascal would have screamed bloody murder
+because of the damage to incremental compilation.
+
+For instance:
+
+   package Leaker is
+       type Int is range 0 .. 100;
+   private
+       Obj : Int; -- Freezes Int.
+   end private; -- I really hate this semicolon; it feels to me as natural as
+                -- "end record" (that is, not at all).
+       for Int'Size use 8; -- Illegal, Int is frozen.
+   end Leaker;
+
+Of course, if Obj is removed, then the rep. clause is allowed.
+
+I can't get too upset about this particular problem (which is why I labeled
+this "quibbles", not "issues"). It could be fixed by simply disallowing
+representation items in secondary visible part for entities declared in the
+primary visible part. That of course would be compatible (there being no
+secondary visible part in older Ada). I think that allowing representation clauses
+far away from their declarations is a major mistake in Ada, and I'd be happy
+to rein that "feature" in somewhat.
+
+But I do wonder if there are other effects of this "freezing leakage" that
+would be more serious. I can't think of any off-hand. But perhaps we need to
+consider freezing everything at the end of the private part (just as we do
+today); then there can be no private freezing leakage.
 
 ****************************************************************
 

Questions? Ask the ACAA Technical Agent