CVS difference for acs/ac-00147.txt

Differences between 1.1 and version 1.2
Log of other versions for file acs/ac-00147.txt

--- acs/ac-00147.txt	2007/10/25 06:08:48	1.1
+++ acs/ac-00147.txt	2008/07/13 01:04:00	1.2
@@ -116,3 +116,620 @@
 
 ****************************************************************
 
+!topic Ada 2005 makes limited private idiom illegal
+!reference 7.5
+!from Adam Beneschan 08-05-21
+!discussion
+
+
+I've run into a problem where an idiom I found useful in Ada 95 is
+no longer allowed in Ada 2005.  
+
+Suppose you have a package whose purpose is to open a communication
+channel to another computer, using Unix sockets:
+
+   package Socket_Communication is
+       type Channel is limited private;
+       function Open_Channel (Computer_Name : String) return Channel;
+       ... other operations
+   private
+       type Channel is record  -- not limited
+          ...
+       end record;
+       ... other definitions
+   end Socket_Communication;
+
+(Note that the full type is not limited, so there wouldn't have been any
+return-by-reference issues in Ada 95.)
+
+Later, you want to write a different communication package for some more
+specialized purpose---say a package that connects to a specified central
+warehouse to get information on the current inventory.  In the abstract,
+you might want the visible part of the package spec to say something like:
+
+   package Warehouses is
+       type Warehouse_Connection is limited private;
+       function Open_Connection (Warehouse_Number : Integer)
+           return Warehouse_Connection;
+
+For the implementation, let's say you decide to implement it using
+Socket_Communication.  Reasonable enough, right?  In general, a
+Warehouse_Connection may need to carry additional information besides
+the Socket_Communication info, but let's say it doesn't.  It seems
+natural to want to implement it as:
+
+   with Socket_Communication;
+   package Warehouses is
+       type Warehouse_Connection is limited private;
+       function Open_Connection (Warehouse_Number : Integer)
+           return Warehouse_Connection;
+       ...
+   private
+       type Warehouse_Connection is new Socket_Communication.Channel;
+       ...
+
+and then implement Open_Connection as
+
+       function Open_Connection (Warehouse_Number : Integer)
+            return Warehouse_Connection is
+           Name : constant String := 
+                    Warehouse_Computer_Name_Of (Warehouse_Number);
+       begin
+           return Warehouse_Connection 
+                    (Socket_Communication.Open_Channel (Name));
+       end Open_Connection;
+
+Seems simple enough, right?  BZZZZZZZT!  It isn't legal.  It was legal
+in Ada 95, but no more, because:
+
+(1) only the partial view of Socket_Communication.Channel is
+    available, and that type has the word "limited" in its definition;
+    therefore Socket_Communication.Channel is limited by 7.5(4);
+
+(2) Warehouse_Connection is derived from Socket_Communication.Channel,
+    and is therefore limited by 7.5(6.1);
+
+(3) 7.5(2.1) and 7.5(2.8) apply, and since a type conversion isn't
+    listed as one of the possible expressions that can appear in a
+    return statement, it isn't legal.
+
+I don't know what the solution is, or if one is needed.  I haven't
+studied things enough to figure out whether type conversions, or certain
+kinds of type conversions, could be allowed in 7.5(2.1).
+
+I actually ran into this while trying to implement both Ada.Text_IO and
+Ada.Wide_Text_IO, putting all the interesting code in Wide_Text_IO and
+implementing Text_IO mostly by making calls to Wide_Text_IO.
+(File_Type is limited private in both packages, so code I had gotten
+working for Ada 95 no longer compiles, for the language-defined functions
+that return File_Type.)  But I think the problem is more general than that.
+I'm not sure how serious it is; the problem can be worked around by making
+the full view of Warehouse_Connection a (nonlimited) record with a
+Socket_Communication.Channel component, but it seems a bit hokey to have
+to do this.
+
+****************************************************************
+
+From: Adam Beneschan
+Sent: Wednesday, May 21, 2008 11:14 AM
+
+> I actually ran into this while trying to implement both Ada.Text_IO 
+> and Ada.Wide_Text_IO, putting all the interesting code in Wide_Text_IO 
+> and implementing Text_IO mostly by making calls to Wide_Text_IO.
+> (File_Type is limited private in both packages, so code I had gotten 
+> working for Ada 95 no longer compiles, for the language-defined 
+> functions that return File_Type.)  But I think the problem is more 
+> general than that.  I'm not sure how serious it is; the problem can be 
+> worked around by making the full view of Warehouse_Connection a
+> (nonlimited) record with a Socket_Communication.Channel component, but 
+> it seems a bit hokey to have to do this.
+
+I must be asleep---the record would still be limited, but you could at
+least write an aggregate in the return statement.  It does seem strange
+that you would have to do that.  It seems that if you can say
+
+   type T2 is record
+      X : T1;  -- T1 is limited
+   end record;
+
+   return T2' (X => Some_Func_Call(...));
+
+you ought to be able to say
+
+   type T2 is new T1;
+
+   return T2 (Some_Func_Call (...));
+
+I don't know whether all type conversions ought to be allowable by 7.5(2.1),
+but at the least it should be OK to allow untagged type conversions where
+the target type is derived from the operand type.
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Wednesday, May 21, 2008 11:43 AM
+
+If it is declared limited, then that means from the outside, you aren't allowed
+to copy it.  The Ada 95 rules implied privacy breakage.
+
+In Ada 2005, function return always involves the creation of a new object, either
+by copying an old one (which isn't allowed if it is limited), or by creating a
+new object with an aggregate or an extended return statement.
+
+If you want some clients to be able to copy it, then you need to make it
+non-limited, or move those clients that want to take advantage of its underlying
+non-limitedness into child packages.
+
+On the other hand, you have illustrated a case where you use non-tagged type
+derivation, and it might be argued that a type conversion between non-tagged
+derived types need not create a new object, presuming there weren't any
+rep-clauses applied to the derived type.
+
+On the other other hand, it seems that either these types are very closely
+related, in which case it would make sense for the derived type to be declared
+in a child package, or they are pretty much unrelated, in which case you could
+define the new type by wrapping the old type in a record with only one component,
+as you suggested.
+
+Or you could make the types tagged, in which case you can use an extension
+aggregate in the return statement.
+
+****************************************************************
+
+From: Robert A. Duff
+Sent: Wednesday, May 21, 2008  4:43 PM
+
+> If it is declared limited, then that means from the outside, you 
+> aren't allowed to copy it.  The Ada 95 rules implied privacy breakage.
+
+Really?  How do the Ada 95 rules break privacy?
+
+An alternative rule would be to allow return-by-copy (e.g. return of a global
+object) if the type is not a build-in-place type.  That would break privacy,
+which is evil.  But the existing Ada 2005 rules break compatibility, which is
+even more evil.  I think ARG made the wrong trade-off between breaking privacy
+and breaking compatibility in this case.
+
+Experiments with AdaCore's bug database show that almost all of the violations
+of the new Ada 2005 rule (return expression must be a function call or
+aggregate) in existing Ada 95 code are the full-type-non-limited case.
+That is, return-by-reference is quite rare in Ada 95, so disallowing that would
+have been much more compatible.  (I suspect some of the return-by-ref cases are
+accidental!)
+
+I guess things get more interesting with generic formal limited private types
+-- some instances use return-by-ref, and some use return-by-copy!
+
+> In Ada 2005, function return always involves the creation of a new 
+> object, either by copying an old one (which isn't allowed if it is 
+> limited), or by creating a new object with an aggregate or an extended 
+> return statement.
+
+It doesn't have to be extended.  You can say "return F(...)", which is equivalent
+to "return R : constant T := F(...);".
+
+P.S. Build-in-place is a very cool feature.  Too bad Ichbiah didn't think of
+it in the first place!
+
+****************************************************************
+
+From: Adam Beneschan
+Sent: Wednesday, May 21, 2008  5:01 PM
+
+> > If it is declared limited, then that means from the outside, you 
+> > aren't allowed to copy it.  The Ada 95 rules implied privacy 
+> > breakage.
+> 
+> Really?  How do the Ada 95 rules break privacy?
+
+That's an interesting question, since the return-by-reference rules in
+Ada 95 are mostly in Dynamic Semantics, and someone (was it you?) pointed
+out to me some time ago that the "privacy breaking" thing doesn't apply to
+what happens at run-time, i.e. dynamic semantics.
+However, a quick textual search of the Ada 95 AARM did find one place where
+return-by-reference was referred to in Static Semantics, in 3.10.2, having
+to do with the accessibility level of a return object.
+Since any detailed analysis of 3.10.2 causes the exception Migraine_Error
+to be raised, I haven't tried to construct an example in detail.
+
+But in a case like this:
+
+   package Pak1 is
+      type T is limited private;
+   private
+      type T is ???;
+   end Pak1;
+   
+   with Pak1;
+   package Pak2 is
+      type T2 is limited private;
+   private
+      type T2 is new Pak1.T;
+   end Pak1;
+
+the rules for determining whether T2 is a return-by-reference type
+(RM95 6.5(11-16)) do seem to imply that one needs to look in the private part
+of Pak1 to answer the question.  And since it seems possible (thanks to RM95
+3.10.2(10)) to create a case where the compiler must determine whether a
+function result type is return-by-reference in order to determine whether
+a program is legal, I guess that does mean there's a privacy breakage.
+That may be the sort of thing Tuck was referring to.
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Wednesday, May 21, 2008 10:36 PM
+
+>> If it is declared limited, then that means from the outside, you 
+>> aren't allowed to copy it.  The Ada 95 rules implied privacy 
+>> breakage.
+> 
+> Really?  How do the Ada 95 rules break privacy?
+
+They break privacy because whether or not you can return a local object
+of the private type is determined by whether the full type is or is
+not a return-by-reference type.
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Wednesday, June 11, 2008 11:39 PM
+
+> On the other hand, you have illustrated a case where you use 
+> non-tagged type derivation, and it might be argued that a type 
+> conversion between non-tagged derived types need not create a new 
+> object, presuming there weren't any rep-clauses applied to the derived 
+> type.
+
+We discussed this issue (allowing a few forms of type conversion for
+build-in-place types) here last July. While that discussion was
+inconclusive, the discussion about whether to make it an AI brought up
+some additional issues which I annotated onto the AC (AC-147). Since
+probably no one here read them, I'll attach them here in an effort to
+lay this idea to rest:
+
+"It is clear that only a few kinds of type conversions would be safe
+in build-in-place contexts. Surely, we couldn't allow anything that
+could change representation or discard portions of a type. That suggests
+that allowing [only safe] kinds of conversions could be confusing for
+the user, as the rules would appear rather arbitrary. Thus, I don't
+think this is a good idea."
+
+The previous discussion suggested allowing conversion to a class-wide type;
+this one suggests allowing non-tagged derived type that don't have
+representation clauses. We could also probably allow conversions between
+a null extension and it's parent. And that's it. I can't imagine a
+much weirder set of rules, and it seems dubious that they would help
+in many real situations (and depending on rep. clauses could break
+privacy, as the rep. clauses can be given in the private part) so I
+still don't think this is a good idea.
+
+****************************************************************
+
+From: Gary Dismukes
+Sent: Thursday, May 22, 2008 12:26 AM
+
+I agree with your assessment Randy.  I don't think it makes sense to
+allow conversions in build-in-place contexts.  The privacy-breaking issue
+in particular is a nonstarter, and allowing just the few cases where
+there couldn't be a problem doesn't seem worth it.
+
+****************************************************************
+
+From: Adam Beneschan
+Sent: Thursday, June 19, 2008  4:48 PM
+
+I'm not convinced this is the same issue at all.  The example I started
+with dealt with a type T2 derived from a limited private type T, and
+the problem of writing a function to return a value of type T2. 
+
+This isn't a build-in-place issue at all, because the build-in-place
+rule for function results (7.5(8.1)) only applies to explicitly limited
+record types (and tasks and protected types), *not* limited private
+types (see AARM 7.5(9.a)).  
+
+As for representation clauses: it appears that the language may allow
+representation items on types derived from private types, as long as the
+private type isn't by-reference, which you have to look at the full view
+of the type to determine (13.1(10)).  If this is true, that a
+representation item may be allowed on a type derived from a private type,
+then there appears to be a privacy breakage in the language rules.
+If it's not allowed, though, then the representation clause shouldn't be
+an issue for the type conversion problem I asked about.
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Saturday, June 28, 2008  4:16 PM
+
+...
+> This isn't a build-in-place issue at all, because the build-in-place 
+> rule for function results (7.5(8.1)) only applies to explicitly 
+> limited record types (and tasks and protected types), *not* limited 
+> private types (see AARM 7.5(9.a)).
+
+True, but for the purposes of legality rules they're treated like
+build-in-place types in order to avoid breaking privacy. After all,
+whether or not a limited private type is build-in-place depends solely
+on the declaration of the full type. That's why the legality rules
+apply to all limited types.
+
+Essentially, these legality rules are "assume-the-worst" when it comes
+to limited private types, because otherwise it would be easy for a
+client to have an implied dependency on the form of the declaration
+of the full type. We don't want clients to become illegal if someone
+adds a protected component, for instance.
+
+> As for representation clauses: it appears that the language may allow 
+> representation items on types derived from private types, as long as 
+> the private type isn't by-reference, which you have to look at the 
+> full view of the type to determine (13.1(10)).  If this is true, that 
+> a representation item may be allowed on a type derived from a private 
+> type, then there appears to be a privacy breakage in the language 
+> rules.  If it's not allowed, though, then the representation clause 
+> shouldn't be an issue for the type conversion problem I asked about.
+
+Representation items generally don't have any effect on legality rules
+(other than for other rep. items). There are a couple of exceptions but
+we really don't want to be adding any more, because rep. items generally
+can be hidden and thus such dependencies break privacy.
+
+You seem to be implying that this sort of conversion should be allowed
+because the full parent type (and derived type) in question don't prevent
+it. But that's backwards to the usual Ada model, where the clients can't
+be made illegal by maintenance on the parent type. I don't think we want
+to be changing that.
+
+****************************************************************
+
+From: Adam Beneschan
+Sent: Wednesday, July 2, 2008  10:20 AM
+
+...
+> Representation items generally don't have any effect on legality rules 
+> (other than for other rep. items). There are a couple of exceptions 
+> but we really don't want to be adding any more, because rep. items 
+> generally can be hidden and thus such dependencies break privacy.
+> 
+> You seem to be implying that this sort of conversion should be allowed 
+> because the full parent type (and derived type) in question don't 
+> prevent it. But that's backwards to the usual Ada model, where the 
+> clients can't be made illegal by maintenance on the parent type. I 
+> don't think we want to be changing that.
+
+I'm having trouble following this and understanding why it argues
+against any point I was making, and perhaps that's because I didn't make
+myself clear enough last time.  Let me try again...
+
+Suppose you write:
+
+    package Pak1 is
+        type T1 is limited private;
+    private
+        type T1 is record
+            F1 : Character;
+            F2 : Integer;
+        end record;
+    end Pak1;
+
+    with Pak1;
+    package Pak2 is
+        type T2 is new Pak1.T1;
+        pragma Pack (T2);        -- legal?
+    end Pak2;
+
+I'm not clear on whether the noted rep clause is legal or not.  I think
+it is---I don't see any rule that makes this illegal.  [Pack is allowed
+on composite subtypes, and 3.2(4.1) says that partial views are composite.]
+
+However, if you changed the full type of T1 to make it "tagged", or "limited",
+or add another component whose type is a tagged record, then T1 becomes a
+by-reference type (even the private view becomes a by-reference view, by
+6.2(9)), and the rep clause is illegal by 13.1(10).
+
+So if your concern is that clients shouldn't be made illegal by maintenance
+on the parent type, it appears that we *already* have a case that violates
+this principle---if the Pack pragma is legal.  
+
+However, if I've missed something, and the Pack clause is actually illegal,
+then I don't see how my "proposal" (see below) causes any new privacy
+breakage problems.
+
+I realize that I don't think I ever made a specific proposal here; I
+pointed out a problem and made some general comments.  Looking back, some
+of those comments seemed to suggest that maybe type conversions should be
+allowed even where private types aren't involved, and that may have been
+incorrect and may have led to some confusion.  So I'm going to try
+something more specific:
+
+I propose changing 7.5(2.1), which currently reads:
+
+    In the following contexts, an expression of a limited type is not
+    permitted unless it is an aggregate, a function_call, or a
+    parenthesized expression or qualified_expression whose operand is
+    permitted by this rule:
+
+to
+
+    In the following contexts, an expression of a limited type is not
+    permitted unless it is an aggregate, a function_call, or a
+    parenthesized expression or qualified_expression whose operand is
+    permitted by this rule, or a type_conversion whose operand is
+    permitted by this rule, if the type_conversion is between a
+    derived type and an ancestor of the derived type, where the
+    ancestor is a limited untagged partial view:
+
+or something to that effect.
+
+I've narrowed this down to cases where a type is derived from an untagged
+limited private type.  If representation clauses on types derived from
+private types are illegal, then I think one of the main objections, that
+such a type conversion could require a copy of a limited object due to a
+representation change, would not apply.  If it's possible to come up with
+a case involving a *chain* of derived types where the type conversion would
+still involve a representation change, perhaps "ancestor" could be changed
+to "parent" in the above.
+
+Anyway, assuming that rep clauses such as the above are illegal, then
+I don't see any privacy breakage concerns with this proposal.
+
+My reasons in support of the proposal:
+
+(1) It eliminates a backward incompatibility---a case where code that
+    was legal in Ada 95 is illegal in Ada 2005.
+
+(2) The code that Ada 2005 made illegal actually came up in practice.
+
+(3) Although some workarounds have been mentioned, such as this in my
+    original example:
+
+    package Pak1 is
+       type T1 is limited private; ...
+
+    package Pak2 is
+       type T2 is limited private;
+    private
+       type T2 is record
+          The_Data : Pak1.T1;
+       end record; ...
+
+    the original case, where the full view of T2 was a derived type:
+
+    package Pak2 is
+       type T2 is limited private;
+    private
+       type T2 is new Pak1.T1; ...
+
+    is not illegal, and it's possible to implement all of Pak2 in that
+    manner.  But later, if it is desired to add a new operation to
+    Pak2 that is a function that returns T2, it's only then that the
+    Pak2 implementor finds that a derived type won't work, and that he
+    therefore needs to redefine T2 and fix all uses of it in the body
+    of T2, which is annoying.
+
+It may also be desirable to modify 13.1(10) to prevent rep clauses on types
+derived from private types, to eliminate the possible privacy breakage that
+comes from making the legality depend on whether the parent type is a
+by-reference type (assuming there isn't some other rule somewhere else that
+already prevents this).
+
+However, if the privacy breakage in 13.1(10) is considered acceptable, then
+I can see how my proposed change to 7.5(2.1) could make things worse from
+a privacy breakage standpoint.
+
+Anyway, I hope this is clearer.
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Wednesday, July 2, 2008  3:59 PM
+
+> I'm not clear on whether the noted rep clause is legal or not.  I 
+> think it is---I don't see any rule that makes this illegal.  [Pack is 
+> allowed on composite subtypes, and
+> 3.2(4.1) says that partial views are composite.]
+
+The ARG cannot agree on much when it comes to pragma Pack (other than
+that we don't want to discuss it anymore), so there can be no definitive
+answer.
+
+However, attribute clauses for 'Size and 'Alignment would be allowed here
+(although a particular implementation could reject them if it wished).
+
+> However, if you changed the full type of T1 to make it "tagged", or 
+> "limited", or add another component whose type is a tagged record, 
+> then T1 becomes a by-reference type (even the private view becomes a 
+> by-reference view, by 6.2(9)), and the rep clause is illegal by 
+> 13.1(10).
+> 
+> So if your concern is that clients shouldn't be made illegal by 
+> maintenance on the parent type, it appears that we
+> *already* have a case that violates this principle---if the Pack 
+> pragma is legal.
+
+I though that is what I said: there are some exceptions for representation
+items that break the privacy model, but we surely don't want to be adding
+any more.
+
+Remember that the following is legal:
+
+     with Pak1;
+     package Pak3 is
+         type T3 is new Pak1.T1;
+     private
+         for T3'Alignment use <some-expr>;
+     end Pak3;
+
+and thus the clients of T3 do not even know if there is a representation
+item on the type.
+
+...
+> I propose changing 7.5(2.1), which currently reads:
+> 
+>     In the following contexts, an expression of a limited type is not
+>     permitted unless it is an aggregate, a function_call, or a
+>     parenthesized expression or qualified_expression whose operand is
+>     permitted by this rule:
+> 
+> to
+> 
+>     In the following contexts, an expression of a limited type is not
+>     permitted unless it is an aggregate, a function_call, or a
+>     parenthesized expression or qualified_expression whose operand is
+>     permitted by this rule, or a type_conversion whose operand is
+>     permitted by this rule, if the type_conversion is between a
+>     derived type and an ancestor of the derived type, where the
+>     ancestor is a limited untagged partial view:
+> 
+> or something to that effect.
+
+This is exactly the extremely narrow (and complex) exception for type conversions
+that pretty much everyone has agreed that we don't want. Especially as it would
+have to break privacy in order to include a rule disallowing a type like T3.
+Also recall that the full type for T1 could easily be immutably limited, and
+then the build-in-place rules would be triggered. A value type conversion is
+considered a copying operation, after all, and trying to redefine this case
+as a view conversion doesn't seem worth the effort.
+
+> I've narrowed this down to cases where a type is derived from an 
+> untagged limited private type.  If representation clauses on types 
+> derived from private types are illegal, then I think one of the main 
+> objections, that such a type conversion could require a copy of a 
+> limited object due to a representation change, would not apply.  If 
+> it's possible to come up with a case involving a *chain* of derived 
+> types where the type conversion would still involve a representation 
+> change, perhaps "ancestor" could be changed to "parent" in the above.
+> 
+> Anyway, assuming that rep clauses such as the above are illegal, then 
+> I don't see any privacy breakage concerns with this proposal.
+
+They're legal, although an implementation could reject them for their own
+reasons (I haven't been able to think of any case covered by the Recommended
+Level of Support).
+ 
+...
+> However, if the privacy breakage in 13.1(10) is considered acceptable, 
+> then I can see how my proposed change to 7.5(2.1) could make things 
+> worse from a privacy breakage standpoint.
+
+I don't think the privacy breakage is acceptable per-se (if it was up to me,
+I would do the entire set of representation items differently), but eliminating
+it could be a significant incompatibility and surely would be a disincentive
+to using private types. I don't think we want such disincentives. And even
+with such a rule change, we'd still need the complex and narrow rule you
+proposed, which at best looks like a wart and at worst looks like something
+added to appease someone.
+
+Indeed the rule reminds me of the speed limit signs in Illinois. When you reach
+the Illinois border, you first see a large "Speed Limit 65" sign. But then
+shortly afterwards you see "Speed Limit 55 <many lines of tiny text>".
+There is never enough time to read the tiny text as you drive by at highway
+speeds. It starts out "Trucks over nnn GW...", but the last few lines could
+hide almost anything. I always tell people that the last time is ", and green
+cars on Tuesdays." (which is relevant because I now drive a dark green
+car.) I doubt that most drivers have actually read the whole list, meaning
+that they have no way to know if it applies to them. I don't think we need
+rules like that in Ada.
+
+****************************************************************
+

Questions? Ask the ACAA Technical Agent