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

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

--- ai05s/ai05-0074-2.txt	2008/08/08 05:21:31	1.3
+++ ai05s/ai05-0074-2.txt	2008/08/14 04:38:09	1.4
@@ -4963,3 +4963,1033 @@
 
 ****************************************************************
 
+From: Dan Eilers
+Date: Friday, August 8, 2008  1:15 PM
+
+> I think there is something elegant about sandwiching a private part in 
+> between two visible parts.  When you start to have a random 
+> alternation between visible and private, you have a jumble rather than 
+> an "abstraction."
+> Remember we are talking here about a "specification"
+> not the implementation.
+
+I disagree that this proposed solution is particularly elegant, although
+it's a reasonable engineering compromise.
+
+Elegance requires consistency with high-level language goals.
+As you note, the purpose of a package spec is to define the visible part
+of an abstraction.  Any mixing of irrelevant private details within that
+spec is inelegant.  The current two-part solution is somewhat elegant
+in that it allows the reader to stop reading when they get to the
+private keyword, but the proposed three-part solution loses that elegance.
+
+Elegance requires consistency with other parts of the language.
+As Randy notes, the proposed three-part solution invites confusion as to
+whether the private part is considered to be a nested structure, or a
+toggled region at the same level.  If it is to be considered a nested
+structure, then this is a shift in mindset, and we should require
+"end private;" even when there is no trailing visible part, because in
+Ada, "end" is never optional.  If it is to be considered a toggled region,
+then the keyword "end" shouldn't be used, because the focus should be
+on beginning the next region rather than ending the previous region.
+To be consistent, you'd have to change the syntax of If statements to
+use "end then;" instead of "else".
+
+Elegance requires minimal restructuring from a user's original attempt.
+But each of the examples in the proposal had to be restructured in order
+to work with the proposal.
+
+In the example:
+
+        package p is
+          type T is private;
+          x: T;   -- obscure error message here about freezing rules
+        private
+          type T is new integer;
+        end p;
+
+Instead of requiring the user to restructure the spec into three parts,
+losing the coherence of the visible part, an elegant solution might say
+that the declaration of x freezes T, and it is illegal for the full type
+of T to directly or indirectly depend on x.  A slightly less elegant
+solution might use a pragma to explicitly freeze T before the declaration
+of x, but with no restructuring.
+
+True elegance requires completeness.  Newton's theory of gravity was
+elegant in unifying falling apples with orbiting celestial bodies, and
+served to land men on the moon.  But it failed to account for some pesky
+corner cases, and had to be superseded for GPS to work right, among other
+things. The three-part package solution similarly works OK for packages
+with a single private type, but falls down in corner cases, such as when
+a private type depends on a visible type which depends on a second private
+type. I think Einstein's famous rule "as simple as possible, but no simpler"
+applies.
+
+****************************************************************
+
+From: Robert Dewar
+Date: Friday, August 8, 2008  1:32 PM
+
+> I think there is something elegant about sandwiching a private part 
+> in between two visible parts.  When you start to have a random 
+> alternation between visible and private, you have a jumble rather 
+> than an "abstraction." Remember we are talking here about a
+> "specification" not the implementation.
+
+To me the private part should be in a separate file anyway, having
+it in any sense as part of the visible spec is junk.
+
+Now with the current definition of Ada, you can indeed put the
+private part in a separate file (that's on the list of GNAT
+enhancements to do some time), and we helped enable this with the
+private with.
+
+I dislike going backwards and forwards because it makes this separation
+more difficult to understand and describe.
+
+Right now, the proper way a client reads a spec is to quit reading
+when you see private. It's like a sign on the door that says
+"authorized personel only".
+
+If we switch backwards and forwards it's more like a sign on the door
+that says
+
+Non-authorized personel are permitted entry solely to see if there
+is a door further on that has unrestricted entry.
+You may not look at anything else other than such a door if you enter
+here.
+
+:-(
+
+> Elegance requires consistency with high-level language goals.
+> As you note, the purpose of a package spec is to define the visible 
+> part of an abstraction.  Any mixing of irrelevant private details 
+> within that spec is inelegant.  The current two-part solution is 
+> somewhat elegant in that it allows the reader to stop reading when 
+> they get to the private keyword, but the proposed three-part solution 
+> loses that elegance.
+
+indeed, see above
+
+Can't we find a more elegant solution here that does not destroy the
+entire structure of private parts?
+
+****************************************************************
+
+From: Randy Brukardt
+Date: Saturday, August 9, 2008  1:28 AM
+
+> Can't we find a more elegant solution here that does not destroy the 
+> entire structure of private parts?
+
+Well, we've been trying for quite a while now, and we aren't any closer
+to an ideal solution.
+
+A limited instantiation (or partial instantiation) would work (see
+AI05-0074-1), but hardly anyone would call it elegant. And it's hard
+to describe in language terms (because the way it looks inside and
+outside of the package are very different, and the client sees more)
+and probably not obvious to users.
+
+Just allowing the instantiation to work without freezing would require
+lots of changes to the freezing rules and also would require changing
+the way (some) instantiations elaborate. Besides the massive impact
+on implementations, it would effectively drop the linear elaboration
+model. Some proposals put the elaboration at some later freezing point,
+which seemed like a maintenance hazard and something only rare users
+could figure out. (Most users only know about the freezing rules when
+they get a compiler error message, and it doesn't seem good to change
+that.)
+
+The only other idea floated was a way to make a child package look
+(naming-wise) like it is part of its parent (and as such, it would
+automatically come along when the parent is withed). But that makes
+a pretty complex structure and doesn't help if the instance exports
+types that need to be used in primitives of the parent package.
+
+So far, the most elegant idea has been to not bother solving the
+problem. :-) But it seems to be an impediment to using the containers,
+so that's not ideal, either.
+
+We all would love to hear an elegant idea for solving this problem
+-- please feel free to suggest one!
+
+****************************************************************
+
+From: Steve Baird
+Date: Friday, August 8, 2008  3:39 PM
+
+How does the "end private" proposal cope with declarations in the
+post-private part which conflict in some sense with declarations
+in the private part?
+
+Perhaps the simplest case is
+
+  package Pkg is
+  private
+    X : Integer;
+  end private
+    X : Float;
+  end Pkg;
+
+8.3(26/2) states
+  A non-overridable declaration is illegal if there is a homograph
+  occurring immediately within the same declarative region that is
+  visible at the place of the declaration, and ... .
+
+This does not seem to apply in this case. Neither X is visible
+at the place of the declaration of the other.
+
+There are similar questions about the overriding relationships
+between declarations in the private part and the post-private part
+of a package.
+
+Given
+
+  package Pkg2 is
+    type Has_No_Foo is tagged null record;
+    type Has_Foo is new Has_No_Foo with null record;
+    procedure Foo (X : Has_Foo);
+
+    type Two_Part is new Has_No_Foo with private;
+  private
+    type Two_Part is new Has_Foo with null record;
+  end private
+    procedure Foo (X : Two_Part);
+  end Pkg2;
+
+does the (second) explicit declaration of Foo override the implicit
+declaration of Foo that occurs at the point of the completion of the
+type Two_Part?
+
+****************************************************************
+
+From: Tucker Taft
+Date: Saturday, August 9, 2008  10:01 AM
+
+...
+> This does not seem to apply in this case. Neither X is visible at the 
+> place of the declaration of the other.
+
+Clearly this must be illegal.  There are special words to make disallow
+child units and subunits from having the same name, and perhaps this
+might need some of the same words.  Clearly it should always be illegal
+to have two distinct homographs declared immediately in the same
+declarative region if there is a place where they might both be visible.
+I guess I had presumed there were already enough rules to ensure that,
+but as you point out, at least the one above doesn't quite accomplish
+the goal.
+ 
+> There are similar questions about the overriding relationships between 
+> declarations in the private part and the post-private part of a 
+> package.
+> 
+> Given
+> 
+>   package Pkg2 is
+>     type Has_No_Foo is tagged null record;
+>     type Has_Foo is new Has_No_Foo with null record;
+>     procedure Foo (X : Has_Foo);
+> 
+>     type Two_Part is new Has_No_Foo with private;
+>   private
+>     type Two_Part is new Has_Foo with null record;
+>   end private
+>     procedure Foo (X : Two_Part);
+>   end Pkg2;
+> 
+> does the (second) explicit declaration of Foo override the implicit 
+> declaration of Foo that occurs at the point of the completion of the 
+> type Two_Part?
+
+Explicit declarations always override inherited subprograms, no matter
+which one comes first.  I would expect the existing rules already cover
+this situation, though as in the case above, the existing rules might
+need more tweaking.
+
+****************************************************************
+
+From: Randy Brukardt
+Date: Saturday, August 9, 2008  7:31 PM
+
+> Explicit declarations always override inherited subprograms, no matter 
+> which one comes first.  I would expect the existing rules already 
+> cover this situation, though as in the case above, the existing rules 
+> might need more tweaking.
+
+It took me a while to figure this out from the wording, but I think
+the existing wording is OK. This is another area where one's head tends to
+feel like it is about to explode. :-)
+
+Anyway, I was worried about anomolies, but so far as I can tell, they all
+already exist (because of "additional characteristics") so it probably
+doesn't matter. At least, I'll let Steve figure that out and let my head
+deflate.
+
+****************************************************************
+
+From: Steve Baird
+Date: Monday, August 11, 2008  11:49 AM
+
+...
+>> does the (second) explicit declaration of Foo override the implicit 
+>> declaration of Foo that occurs at the point of the completion of the 
+>> type Two_Part?
+
+> Explicit declarations always override inherited subprograms, no matter 
+> which one comes first.
+
+I agree with you, but overriding something that you aren't allowed to see
+seems odd.
+
+This becomes clearer if we add an overriding indicator to the final
+explicit declaration of Foo:
+
+   overriding procedure Foo (X : Two_Part);
+
+Now the legality of this declaration depends on the contents of a
+private part that it is not supposed to be able to see into.
+This is not unprecedented (rep clause checking, detection of recursive
+types), but it is not the sort of thing we want to encourage.
+
+I suppose you could tweak the rules for overriding indicators to somehow
+disallow the indicator in this case (while continuing to disallow a
+"not overriding" indicator).
+
+On the other hand, one could argue that we aren't really doing serious
+damage to the privacy model here because this is all within one package
+spec.
+
+What do you think?
+
+I realize that this may be a case of prematurely diving into the low-level
+details, but I think it is useful to point out that this proposal may turn
+out to be more complicated than it seems at first.
+
+****************************************************************
+
+From: Tucker Taft
+Date: Tuesday, August 12, 2008  5:49 AM
+
+...
+> I agree with you, but overriding something that you aren't allowed to 
+> see seems odd.
+
+The overriding is only relevant at a place where both are visible, so
+I don't see that there is an anomaly.
+ 
+> This becomes clearer if we add an overriding indicator to the final 
+> explicit declaration of Foo:
+> 
+>    overriding procedure Foo (X : Two_Part);
+> 
+> Now the legality of this declaration depends on the contents of a 
+> private part that it is not supposed to be able to see into.
+> This is not unprecedented (rep clause checking, detection of recursive 
+> types), but it is not the sort of thing we want to encourage.
+
+Isn't this more similar to the case where you have a private extension,
+and you override an operation that is *not* inherited from the ancestor
+of the private extension, but *is* inherited from the actual parent
+subtype specified on the full record extension?
+
+Using this as a model, then the overriding indicator would *not* be
+permitted.  However, similarly, "not overriding"
+would not be permitted, because eventually the declaration
+*is* overriding (in the body).
+ 
+> I suppose you could tweak the rules for overriding indicators to 
+> somehow disallow the indicator in this case (while continuing to 
+> disallow a "not overriding" indicator).
+
+I don't see the "tweak" needed, presuming it doesn't override until
+you get to a point where they both are visible.
+ 
+> On the other hand, one could argue that we aren't really doing serious 
+> damage to the privacy model here because this is all within one 
+> package spec.
+> 
+> What do you think?
+
+I don't think the overriding would be relevant until the body, which
+is why neither "overriding" nor "not overriding" would be legal.
+
+> I realize that this may be a case of prematurely diving into the 
+> low-level details, but I think it is useful to point out that this 
+> proposal may turn out to be more complicated than it seems at first.
+
+This one doesn't seem to be a problem to me, based on the current wording.
+
+The other problem you mentioned, where a declaration should be illegal
+because it is a homograph of a non-overridable declaration, does seem
+to need some kind of wording fix.
+
+Paragraph 8.3(26/2) starts:
+
+   A non-overridable declaration is illegal if there is a homograph
+   occurring immediately within the same declarative region that is
+   visible at the place of the declaration, and is not hidden from
+   all visibility by the non-overridable declaration...
+
+We could either add a special case for this new case, or modify the above
+wording as follows:
+
+   A non-overridable declaration is illegal if there is a homograph
+   occurring immediately within the same declarative region that is
+   visible at the place of the declaration{, or becomes visible
+   somewhere later within its scope}, and is not hidden from
+   all visibility by the non-overridable declaration...
+
+****************************************************************
+
+From: Robert A. Duff
+Date: Tuesday, August 12, 2008  11:21 AM
+
+> I agree with you, but overriding something that you aren't allowed to 
+> see seems odd.
+> 
+> This becomes clearer if we add an overriding indicator to the final 
+> explicit declaration of Foo:
+> 
+>    overriding procedure Foo (X : Two_Part);
+> 
+> Now the legality of this declaration depends on the contents of a 
+> private part that it is not supposed to be able to see into.
+
+I think privacy breakage within a single package is not really privacy
+breakage.  Breaking privacy means that _client_ legality depends on
+private parts of with-ed packages.
+
+****************************************************************
+
+From: Steve Baird
+Date: Tuesday, August 12, 2008  4:23 PM
+
+Given:
+   package Pkg2 is
+     type Has_No_Foo is tagged null record;
+     type Has_Foo is new Has_No_Foo with null record;
+     procedure Foo (X : Has_Foo);
+
+     type Two_Part is new Has_No_Foo with private;
+   private
+     type Two_Part is new Has_Foo with null record;
+   end private
+     overriding procedure Foo (X : Two_Part); -- legal?
+   end Pkg2;
+
+Steve said:
+> I suppose you could tweak the rules for overriding indicators to 
+> somehow disallow the indicator in this case (while continuing to 
+> disallow a "not overriding" indicator).
+
+Tuck said:
+> I don't see the "tweak" needed, presuming it doesn't override until 
+> you get to a point where they both are visible.
+
+8.3.1(5/2) says
+   "If ..., then the operation shall override a homograph at
+    the place of the declaration ..."
+ 
+Section 8.3 gives clear rules about whether a given declaration overrides
+another declaration, but it is less clear in defining the point at
+which the overriding occurs. One definition would be "at the second
+of the two declarations". Another would be "at the earliest point where
+both of the two declarations are directly visible" (I think we both favor
+this choice). Without post-private parts, these two definitions are
+equivalent. With post-private parts, I think that some form of
+clarification (perhaps just an AARM note) would be needed.
+
+I'd certainly concede that this is a minor point.
+
+****************************************************************
+
+From: Robert A. Duff
+Date: Tuesday, August 12, 2008  11:35 AM
+
+> I am trying to solve a problem I have run into
+> *many* times with minimal disruption to the Ada private-type model.  
+> You are suggesting an approach that would really make more sense in a 
+> completely new language.  One of Bob Duff's ideas (if I remember it 
+> correctly) was to eliminate all elaboration from specs, and thereby 
+> eliminate all linear-elaboration order restrictions from them.
+> I think that has some real appeal, but it ain't Ada.
+
+My idea has all kinds of nice properties:
+
+    - Preserves linear elaboration model.
+
+    - Eliminates the need for freezing rules (which no programmer understands!)
+      and access-before-elab run-time checks.
+
+    - Less restrictive.  E.g. it is possible to do something like:
+
+        package Big_Nums is
+            type Big_Num is private;
+            function Value (S : String) return Big_Num;
+            Zero : constant Big_Num := Value ("0");
+
+      which doesn't work in Ada.  Same issue as the instantiations we're
+      talking about here.
+
+    - A module _spec_ can import its own children, without the requirement for
+      pointers we have for "limited with".
+
+    - Checks all the rules at compile time, except in certain cases where
+      link-time checks are required.  ("Certain cases" = cyclic dependences
+      among modules.)
+
+    - Elab order is fully portable.
+
+    - Elab order can be calculated "locally" -- it depends only on the
+      dependences between siblings (as opposed to Ada, where adding a
+      long-distance with clause can require recalculating the order for the
+      whole program).  This makes it more incremental.
+
+    - When reading the body, you can tell which declarations are public without
+      switching over to look at the spec.
+
+But...
+
+> Bob might want to "elaborate" further... ;-)
+
+I'm not sure I see the point, since as you say, "it ain't Ada".
+I doubt my ideas can be inserted into Ada without major incompatible
+changes to Ada.
+
+****************************************************************
+
+From: Randy Brukardt
+Date: Wednesday, August 13, 2008  2:13 PM
+
+Bob Duff writes: 
+
+...
+Seems like all goodness here. What's the catch? There must be one,
+especially as no details are given as to how you accomplish the above.
+
+One obvious question, given the example above, when does the elaboration
+(initialization if you prefer) of Zero occur? How do you prevent
+dependence on uninitialized things (that is, things that were not
+elaborated yet)? (Imagine that Value depends on a local object to
+the body of Big_Nums, perhaps a performance counter.)
+
+It's well known that the run-time elaboration checks of Ada aren't
+really needed (if you are willing to take a few more restrictions),
+but it isn't at all obvious how to avoid the other limitations of
+the linear elaboration model without adding erroneousness.
+
+****************************************************************
+
+From: Robert A. Duff
+Date: Wednesday, August 13, 2008  3:39 PM
+
+> Seems like all goodness here.
+
+:-)
+
+>...What's the catch?
+
+The catch is that it ain't Ada.  ;-)
+
+>... There must be one,
+> especially as no details are given as to how you accomplish the above.
+
+I'm not sure I want to go into full detail, since I don't think
+these ideas are relevant to Ada.  Maybe later, especially if you
+goad me some more...  ;-)
+
+> One obvious question, given the example above, when does the 
+> elaboration (initialization if you prefer) of Zero occur?
+
+All elaboration happens in the body.  Specs are not elaborated.  Specs
+are a purely compile time thing, with no presence whatsoever at run time.
+Specs are a description of what's exported by the module.  Specs are all
+about visibility, and have nothing to do with elaboration/initialization.
+
+One of the "details" I didn't mention is that everything exported has to
+have two decls -- one in the spec, one in the body.  Most things work this
+way in Ada (since most exported things are subprograms).  In my language,
+you have:
+
+    Zero : Big_Num := Value ("0"); -- constant is the default in my language!
+
+in the spec, and:
+
+    public Zero : Big_Num := public Value ("0");
+
+in the body, and this body decl is elaborated where it occurs.
+The first "public" indicates that the name Zero is exported, and the
+second "public" indicates that the initial value is also exported.  If
+you wanted something like a deferred constant in Ada, it would be:
+
+    Zero : Big_Num;
+
+in the spec, and:
+
+    public Zero : Big_Num := Value ("0");
+
+in the body.
+
+>... How do you prevent dependence
+> on uninitialized things (that is, things that were not elaborated yet)?
+> (Imagine that Value depends on a local object to the body of Big_Nums,  
+>perhaps a performance counter.)
+
+The body-decl of Zero must occur after the body-decl of Value, which must
+occur after the local object you mentioned.
+These things are elaborated (only in the body!) in that order.
+
+> It's well known that the run-time elaboration checks of Ada aren't 
+> really needed (if you are willing to take a few more restrictions), 
+> but it isn't at all obvious how to avoid the other limitations of the 
+> linear elaboration model without adding erroneousness.
+
+****************************************************************
+
+From: Tucker Taft
+Date: Wednesday, August 13, 2008  6:56 PM
+
+Modula-3 talks about "revelations" rather than "declarations" I believe.
+It is a somewhat similar idea. The module "spec" merely "reveals" some
+parts of the module. It doesn't by itself declare or elaborate anything.
+
+****************************************************************
+
+From: Robert A. Duff
+Date: Wednesday, August 13, 2008  11:21 PM
+
+> One of the "details" I didn't mention is that everything exported has 
+> to have two decls -- one in the spec, one in the body.  Most things 
+> work this way in Ada (since most exported things are subprograms).  In 
+> my language, you have:
+...
+
+I see. It's the second declaration that is the catch, and that's why
+it's not Ada (and can't be in any practical sense).
+
+I'm not sure there is any real need for "public" in these declarations
+(if you want to see what's exported, look at the spec!)
+
+Anyway, thanks for enlightening us. Back to the Ada salt mines. ;-)
+
+****************************************************************
+
+From: Jean-Pierre Rosen
+Date: Friday, August 8, 2008  2:39 AM
+
+Here is a possible alternative to "end private". If it raises sufficient
+interest, I'll write up an AI...
+
+During discussions, it struck me that all this could be accomplished
+with subpackage. I.e. Randy's example could be written as:
+
+with Gen;
+package Abc is
+    package Inner is
+       type X is private;
+       procedure Foo(X : Integer);
+    private
+       type X is record null; end record;
+    end Inner;
+
+    use Inner;
+    package P is new Gen(X);
+    procedure Foo(P : X) renames P.Fum;
+end Abc;
+
+But of course, we don't want to impose the burden of adding the
+extra "Inner." to all users. So my proposal is to allow "anonymous
+packages":
+
+with Gen;
+package Abc is
+    package is
+       type X is private;
+       procedure Foo(X : Integer);
+    private
+       type X is record null; end record;
+    end;
+
+    package P is new Gen(X);
+    procedure Foo(P : X) renames P.Fum;
+end Abc;
+
+Everything declared in an anonymous package would belong to
+the scope of the enclosing construct (so, no use clause needed).
+Except for that, all the rules would be the same as for regular
+packages.
+
+Benefits:
+- All rules are defined by the current rules => simpler model
+- At first sight (pending more discussion), we could allow multiple
+  anonymous packages, maybe nested anonymous packages. Note that the
+  same identifier could not be defined in two different anonymous
+  packages, since they both belong to the enclosing scope.
+
+Drawbacks:
+- Syntactically slightly more complicated than "end private"
+- If multiple anonymous packages are allowed, there is an issue with
+  the package bodies. How do we recognize them? I see at least three
+  possibilities:
+  1) (anonymous) package bodies must be in the same textual order as
+      the specifications
+  2) provide only one body for all specs
+  3) provide no package body at all. The completions would be directly
+     part of the enclosing construct (consistent with the fact that
+     entities declared in anonymous packages are, in effect, part of
+     this enclosing construct).
+
+We might well discover other benefits of anonymous packages: for
+example, for grouping a tagged type and its primitive operations, making
+like a "class" construct.
+
+OK, just let me the time to put my asbestos suite on...
+
+****************************************************************
+
+From: Robert Dewar
+Date: Sunday, August 10, 2008  11:09 AM
+
+Well I can't see that the second example here is enough of a gain on
+the first one to justify adding this mechanism, what's the big deal
+in choosing a name (almost always useful anyway) and adding a use clause?
+
+****************************************************************
+
+From: Robert A. Duff
+Date: Tuesday, August 12, 2008  11:17 AM
+
+The difference is in the client view.  In the first example, the 
+client has to say both "with Abc" and "with Abc.Inner", and then
+either "Abc.Inner.Whatever", or "use Abc.Inner".  The second example
+makes it as if the stuff in the inner package is declared immediately
+within Abc.  In other words, it allows the existence of the inner
+package to be an invisible implementation detail.
+
+This idea reminds me of another one, which I think we discussed a
+while back:
+Have a way to import the entire content of a package (nested or not)
+into another package, making it as if all those declarations appear
+in the second package.  This allows to present to clients a single
+package as an interface, while splitting it up into several for
+convenience of implementation.
+
+****************************************************************
+
+From: Jean-Pierre Rosen
+Date: Monday, August 11, 2008  3:06 AM
+
+> Well I can't see that the second example here is enough of a gain on 
+> the first one to justify adding this mechanism, what's the big deal in 
+> choosing a name (almost always useful anyway) and adding a use clause?
+
+Actually, I think one of the early proposals was to define a package
+that would automatically be "used". I don't remember why the proposal
+was withdrawn, but probably under pressure of the gang of anti-users...
+
+I agree with you, but it's a different issue: is it broken enough to
+justify the "end private"?
+
+****************************************************************
+
+From: Robert A. Duff
+Date: Tuesday, August 12, 2008  3:45 PM
+
+I don't know, but the "signature generic" idea that Tuck trots out now
+and then is a pretty compelling example.  Maybe we all need some more
+examples of such, to convince us of the value.  This is related to
+Ada.Containers.
+
+****************************************************************
+
+From: Jean-Pierre Rosen
+Date: Wednesday, August 13, 2008 12:37 AM
+
+Yes, sure, but is there an example that cannot be solved with nested
+packages? If not, it turns the issue from "impossibility" to
+"inconvenience".
+
+BTW, my proposal is not that different. If you read "package is" as
+"public", "private" as "private" :-) and "end" as "end private",
+it is pretty much equivalent to Tuck's proposal. But the idea is
+that by basing it on an existing notion, it would make it easier to
+answer many questions simply by saying: "just as for a regular
+subpackage".
+
+****************************************************************
+
+From: Randy Brukardt
+Date: Wednesday, August 13, 2008  3:17 PM
+
+> Yes, sure, but is there an example that cannot be solved with nested 
+> packages? If not, it turns the issue from "impossibility" to 
+> "inconvenience".
+
+There are such examples, because nested packages don't allow the declaration of primitive operations of the outer type. But "public" doesn't work for that, either.
+
+Consider an example like (based on a Claw abstraction):
+
+    package Menus is
+        type Menu_Item_Type is tagged private;
+        type Menu_Item_List_Type is array (Positive range <>) of Menu_Item;
+
+        procedure Make_Submenu (Menu_Item : in out Menu_Item_Type;
+                                New_Submenu : in Menu_Item_List_Type);
+            -- Make Menu_Item into a submenu with the given items.
+
+        function Get_Submenu (Menu_Item : in Menu_Item_Type) return
+               Menu_Item_List_Type;
+
+        -- Many other operations here.
+    private
+        type Menu_Item_Type is ...;
+    end Menus;
+
+Make_Submenu and Get_Submenu are primitive, dispatching operations of Menu_Item_Type.
+
+Now, imagine that you want to have a version of Make_Submenu for vectors of menu items. (This seems a very reasonable thing to want to do, especially given the difficulty of handling arrays with unknown bounds.)
+
+The basic conversion would look like:
+
+    with Ada.Containers.Vectors;
+    package Menus is
+        type Menu_Item_Type is tagged private;
+        package Menu_Vector is new Ada.Containers.Vectors (Menu_Item_Type);
+-- Illegal!
+
+        procedure Make_Submenu (Menu_Item : in out Menu_Item_Type;
+                                New_Submenu : in Menu_Vector.Vector'Class);
+            -- Make Menu_Item into a submenu with the given items.
+
+        function Get_Submenu (Menu_Item : in Menu_Item_Type) return
+               Menu_Vector.Vector'Class;
+
+        -- Many other operations here.
+    private
+        type Menu_Item_Type is ...;
+    end Menus;
+
+but as noted, this is illegal because Menu_Item_Type is not completed at the point of the instantiation (and thus freezing it is illegal). [I added the 'Class because a Vector is a tagged type, and non-primitive parameters of a tagged specific type are du
bious: they would not work with extensions and that defeats the purpose of taggedness.]
+
+Trying Tucker's proposal:
+
+    with Ada.Containers.Vectors;
+    package Menus is
+        type Menu_Item_Type is tagged private;
+    private
+        type Menu_Item_Type is ...;
+    public
+        package Menu_Vector is new Ada.Containers.Vectors (Menu_Item_Type);
+
+        procedure Make_Submenu (Menu_Item : in out Menu_Item_Type;
+                                New_Submenu : in Menu_Vector.Vector'Class);
+-- Illegal!
+            -- Make Menu_Item into a submenu with the given items.
+
+        function Get_Submenu (Menu_Item : in Menu_Item_Type) return
+               Menu_Vector.Vector'Class; -- Illegal!
+
+        -- Many other operations here.
+    end Menus;
+
+but now the primitive operations are illegal because you can't declare primitive operations for a type (Menu_Item_Type) after the type is frozen.
+
+Tucker had proposed using renames-as-body to get around that, but that doesn't work here because we donít have visibility on the type Menu_Vector.Vector before the instance.
+
+There is also a complication if Menu_Item_Type needs an
+access-to-Menu_Item_Vector: you'd need to use a Taft-incomplete type in the private part which would be completed in the body (probably with a subtype).
+
+A named nested package doesn't work either: (I'm using a named one here so it is clear what is going on, but the extension to Jean-Pierre's proposal should be obvious.)
+
+    with Ada.Containers.Vectors;
+    package Menus is
+        package Inner is
+           type Menu_Item_Type is tagged private;
+           -- Many other operations here.
+        private
+           type Menu_Item_Type is ...;
+        end Inner;
+        package Menu_Vector is new Ada.Containers.Vectors (Inner.Menu_Item_Type);
+
+        procedure Make_Submenu (Menu_Item : in out Inner.Menu_Item_Type;
+                                New_Submenu : in Menu_Vector.Vector);
+            -- Make Menu_Item into a submenu with the given items.
+
+        function Get_Submenu (Menu_Item : in Inner.Menu_Item_Type) return
+               Menu_Vector.Vector;
+
+    end Menus;
+
+This works, but the routines Make_Submenu and Get_Submenu are no longer primitive. If you need them for dispatching purposes, you are sunk. Again, you also need a Taft-incomplete type in the private part.
+
+At one point, Tucker had suggested making this Vector type private to get it
+exported:
+
+    with Ada.Containers.Vectors;
+    package Menus is
+        type Menu_Item_Type is tagged private;
+        type Menu_Vector_Type is tagged private;
+
+        procedure Make_Submenu (Menu_Item : in out Menu_Item_Type;
+                                New_Submenu : in Menu_Vector_Type'Class);
+            -- Make Menu_Item into a submenu with the given items.
+
+        function Get_Submenu (Menu_Item : in Menu_Item_Type) return
+               Menu_Vector_Type'Class;
+
+        -- Many other operations here.
+    private
+        type Menu_Item_Type is ...;
+        package Menu_Vector is new Ada.Containers.Vectors (Inner.Menu_Item_Type);
+        type Menu_Vector_Type is new Menu_Vector.Vector with null record;
+    end Menus;
+
+[The 'Class is required here, else we'd have a primitive of two tagged types at once.] Now we have a legal spec., but we no longer have a visible vector type, so we'd have to manually export all of the vector operations. This does get rid of the Taft-inco
mplete type, so it is not all bad.
+
+I can't think of any way to make this work with the rules Tucker proposed.
+However, we could make it work if we allowed a private type to be completed in the *second* visible part:
+
+    with Ada.Containers.Vectors;
+    package Menus is
+        type Menu_Item_Type is tagged private;
+        type Menu_Vector_Type is tagged private;
+
+        procedure Make_Submenu (Menu_Item : in out Menu_Item_Type;
+                                New_Submenu : in Menu_Vector_Type'Class);
+            -- Make Menu_Item into a submenu with the given items.
+
+        function Get_Submenu (Menu_Item : in Menu_Item_Type) return
+               Menu_Vector_Type'Class;
+
+        -- Many other operations here.
+    private
+        type Menu_Item_Type is ...;
+    public
+        package Menu_Vector is new Ada.Containers.Vectors (Inner.Menu_Item_Type);
+        type Menu_Vector_Type is new Menu_Vector.Vector with null record;
+    end Menus;
+
+Now we do have the right visibility on Menu_Vector_Type to know that it is a Vector. As an added bonus, the vector operations are inherited here, so they have the same visibility as the type Menu_Vector_Type.
+
+This problem *can* be solved with my limited instance proposal (see
+AI05-0074-1):
+
+    with Ada.Containers.Vectors;
+    package Menus is
+        type Menu_Item_Type is tagged private;
+        package Menu_Vector is limited new Ada.Containers.Vectors
+(Menu_Item_Type);	
+
+        procedure Make_Submenu (Menu_Item : in out Menu_Item_Type;
+                                New_Submenu : in Menu_Vector.Vector'Class);
+            -- Make Menu_Item into a submenu with the given items.
+
+        procedure Get_Submenu (Menu_Item : in Menu_Item_Type;
+                               Submenu : out Menu_Vector.Vector'Class);
+
+        -- Many other operations here.
+    private
+        type Menu_Item_Type is ...;
+        package Menu_Vector is new Ada.Containers.Vectors (Menu_Item_Type);
+    end Menus;
+
+But note that we had to change Get_Submenu to a procedure in order to do it (parameters of tagged limited types are allowed, return values of them are not allowed). As an added bonus, no Taft-incomplete type is needed in the private part, as the instantia
tion provides the needed limited view.
+
+But I'm not pushing very hard for this solution, because the client view of the "limited" instance is *not* limited, and that's pretty weird (even though it works fine semantically). I haven't been able to think of syntax that makes that dichotomy clear, 
and I think it needs to be fairly clear.
+
+The question has to be whether this (and similar corner cases) are important enough to make a solution for. Most of the examples can be solved with nested or child packages; while that is not ideal, it may be enough.
+
+****************************************************************
+
+From: Robert A. Duff
+Date: Wednesday, August 13, 2008  4:57 PM
+
+> Now, imagine that you want to have a version of Make_Submenu for 
+> vectors of menu items. (This seems a very reasonable thing to want to 
+> do, especially given the difficulty of handling arrays with unknown 
+> bounds.)
+
+Very reasonable indeed.  I'd say that vectors should behave _exactly_
+like arrays, except that vectors are growable.  We're pretty far from that
+goal, though.
+
+> [The 'Class is required here, else we'd have a primitive of two tagged 
+> types at once.] Now we have a legal spec., but we no longer have a 
+> visible vector type, so we'd have to manually export all of the vector operations.
+
+So what do you think of the idea I mentioned yesterday -- a syntactic
+shorthand that means "rename all the stuff from one place into another".
+
+****************************************************************
+
+From: Randy Brukardt
+Date: Wednesday, August 13, 2008  7:08 PM
+
+...
+> > Now, imagine that you want to have a version of Make_Submenu for 
+> > vectors of menu items. (This seems a very reasonable thing to want 
+> > to do, especially given the difficulty of handling arrays with 
+> > unknown bounds.)
+> 
+> Very reasonable indeed.  I'd say that vectors should behave _exactly_ 
+> like arrays, except that vectors are growable.
+> We're pretty far from that goal, though.
+
+Well, I do think that user-defined indexing, dereferences, and literals
+would surely be valuable additions to Ada. The only issue is whether
+they can be done cheaply enough. (Note that we sort of have user-defined
+selection via the prefixed view mechanism.)
+
+> > [The 'Class is required here, else we'd have a primitive of two 
+> > tagged types at once.] Now we have a legal spec., but we no longer 
+> > have a visible vector type, so we'd have to manually export all of
+> the vector operations.
+> 
+> So what do you think of the idea I mentioned yesterday -- a syntactic 
+> shorthand that means "rename all the stuff from one place into 
+> another".
+
+I don't think that would help this particular example; as I noted in
+my original note, nested packages (or child packages) don't work. So
+renaming the contents of such a unit don't help, either.
+
+In the wider view, I'd be somewhat concerned about the name pollution
+that would result (you'd need a number of nested or child packages to
+create the small views that would then be combined into the usual
+public face). I'd also worry somewhat that the source code wouldn't
+reflect the actual declarations. We already have that problem with
+inherited routines, and it can be quite severe: it's often necessary
+to have some tool support to figure out what is actually declared
+where. (Overriding indicators provide a [very] poor-mans way of
+figuring that out.)
+
+But I don't want to rule any idea out-of-hand, as nothing has worked
+that well so far...
+
+****************************************************************
+
+From: Tucker Taft
+Date: Wednesday, August 13, 2008  7:37 PM
+
+...
+> Yes, sure, but is there an example that cannot be solved with nested 
+> packages? If not, it turns the issue from "impossibility" to 
+> "inconvenience".
+> 
+> BTW, my proposal is not that different. If you read "package is" as 
+> "public", "private" as "private" :-) and "end" as "end private", it is 
+> pretty much equivalent to Tuck's proposal. But the idea is that by 
+> basing it on an existing notion, it would make it easier to answer 
+> many questions simply by saying: "just as for a regular subpackage".
+
+
+I believe that in several of the examples I gave, a generic
+instantiation is followed by one or more type derivations used to
+effectively rename the type into the outer scope, and to in some cases
+complete an incomplete type.
+I don't see how in a nested package you could complete an incomplete type
+declared in the outer package.
+
+****************************************************************
+

Questions? Ask the ACAA Technical Agent