CVS difference for ai05s/ai05-0159-1.txt
--- ai05s/ai05-0159-1.txt 2010/08/13 05:32:36 1.13
+++ ai05s/ai05-0159-1.txt 2010/10/21 05:53:30 1.14
@@ -1837,3 +1837,1091 @@
****************************************************************
+From: Martin Dowie
+Date: Monday, June 28, 2010 5:10 PM
+
+Just wondering what I'm missing in the latest version of this AI...
+
+
+How are the queues expected to be implemented? e.g.
+
+
+with System;
+with Ada.Containers.Synchronized_Queue_Interfaces;
+
+generic
+ with package Queue_Interfaces is
+ new Ada.Containers.Synchronized_Queue_Interfaces (<>);
+package Ada.Containers.Bounded_Synchronized_Queues is
+ pragma Preelaborate (Bounded_Synchronized_Queues);
+
+
+ -- ******************************************************
+
+ -- No mention of an array type to hold the elements here
+ -- e.g. could have written:
+ -- type Queue_Elements_Type is private;
+ -- ******************************************************
+
+
+ protected
+ type Queue (Capacity : Count_Type;
+ Ceiling : System.Any_Priority) is
+ new Queue_Interfaces.Queue with
+ pragma Priority (Ceiling);
+
+ entry Enqueue (New_Item : Queue_Interfaces.Element_Type);
+ entry Dequeue (Element : out Queue_Interfaces.Element_Type);
+ function Current_Use return Count_Type;
+ function Peak_Use return Count_Type;
+ private
+ -- ******************************************************
+
+ -- Can't define an array type to hold the elements here
+ -- Can't use an anonymous array type
+ -- Can't instantiate a bounded container package
+ -- ******************************************************
+
+ Q : <??????????>;
+ end Queue;
+
+end Ada.Containers.Bounded_Synchronized_Queues;
+
+
+****************************************************************
+
+From: Randy Brukardt
+Date: Monday, June 28, 2010 8:53 PM
+
+The same would be true of the access types needed to implement the root of the data structures for the unbounded forms - they can't be written in the private part of the protected types either. (Anonymous types can't be used, you need to be able to deallo
cate them.)
+
+Generally, the rule for language-defined packages is that it is OK to add things that don't change the semantics of the package as viewed from a client. That means that pragmas, incomplete type declarations for visible entities, and a few other things are
allowed. But adding type declarations are not. It would be a very bad idea to change this (it would defeat the entire point of privacy).
+
+The most important point about the predefined containers is that there is no restriction or requirements on how they are implemented. Thus, the contents of private parts have to be left totally to implementors, and that has to include the ability to decla
re any types they need. The private parts of protected types don't support that (for good reasons: nested type declarations cause various language nightmares).
+
+The only options that I can come up with:
+(1) Have the implementors put the types into the private part of the interface package. But those aren't visible in the protected object's private part unless it is (a) a parent unit and (b) some visibility rules are changed for the language as a whole. N
ot very promising.
+(2) Add some junk private type(s) to the definition to be used in the private part of the protected objects (and for no other purpose). [This is my understanding of your suggestion.] But then, those type(s) have to be documented (what are they for? what
are the requirements on their streaming and equality operators? etc.). And that would be *very* limiting, as it would mean that the components could only have one particular design. (That would be completely inappropriate for the unbounded versions, and pr
obably would be annoying even for the bounded versions as the implementation would be wildly different than the other containers.) There is no way this would even fly.
+(3) Get rid of the explicit protected objects and switch back to private types. However, there then is no sane way to require these to be implemented by protected objects -- there is no such thing as private protected (or task for that matter) types.
+
+None of these seem remotely like good ideas. My initial reaction is to completely give up and junk the entire thing. I suppose that is more frustration than logic talking, but the only one of the above that can even be considered is (3) -- and that means
reintroducing the priority issues that we just tried to address (there being no way to require such private types to be implemented by protected objects, thus there is no sane way to specify the priority.
+
+Other ideas are welcome, but any idea has to allow for any arbitrary implementation of the private part of the protected objects, and can't make the contents of that part (or any of the types used to declare it) visible to clients of the queues. Those req
uirements don't allow many organizations of these packages.
+
+****************************************************************
+
+From: Edmond Schonberg
+Date: Monday, June 28, 2010 9:12 PM
+
+Shouldn't the structure be:
+
+
+with System;
+with Ada.Containers.Synchronized_Queue_Interfaces;
+
+generic
+ with package Queue_Interfaces is
+ new Ada.Containers.Synchronized_Queue_Interfaces (<>);
+package Ada.Containers.Bounded_Synchronized_Queues is
+ pragma Preelaborate (Bounded_Synchronized_Queues);
+
+type Queue (Capacity : Count_Type;
+ Ceiling : System.Any_Priority) is
+ new Queue_Interfaces.Queue with private;
+ ...
+private
+ -- whatever auxiliary types are needed.
+
+
+
+ protected
+ type Queue (Capacity : Count_Type;
+ Ceiling : System.Any_Priority) is
+ new Queue_Interfaces.Queue with
+ pragma Priority (Ceiling);
+
+
+
+ ...
+
+
+end Ada.Containers.Bounded_Synchronized_Queues;
+
+****************************************************************
+
+From: Randy Brukardt
+Date: Monday, June 28, 2010 10:26 PM
+
+That's the structure I was talking about as choice (3) - (although I think you need the keyword "synchronized" in the private type), but we don't ever give any of the contents of the private part. So I don't see any way to require the implementation with
a protected type or the meaning of the priority. Well, other than text to that effect, but I don't recall any other of the predefined libraries where we required a particular implementation. So that seems wrong to me (maybe it cannot be helped); if somethi
ng is important, it ought to be in the contract, not in words.
+
+All of this implies to me that there is something wrong with the design of Ada and interfaces so far as requiring the implementation by a protected type. That seems to be important semantic information, yet Ada has no way to declare that a private type mu
st be implemented by a protected type. Well, there is one way to do that: make the interface protected, which was rejected the last time. Perhaps we ought to add:
+ type Protected_Queue is protected interface and Queue;
+and then derive the concrete types from Protected_Queue?? That would eliminate the need for word for at least the requirement to implement as a protected type. (We'd still have to add wording to require the ceiling priority to be that of the Ceiling discr
iminant.)
+
+In any case, this is very aggravating to do, as it will require reverting the entire AI to the previous version and then trying to apply the other changes back to it (the profiles of the routines being so different that it isn't sensible to try to repair
them all individually; it took three iterations to get this set of protected changes right). And this is such a major change that the entire thing will have to go back for another vote, no way to treat this as a "typo"!!
+
+****************************************************************
+
+From: Martin Dowie
+Date: Tuesday, June 29, 2010 1:45 AM
+
+Or...
+
+
+...resurrect (some form of) AI05-0074!!
+
+
+E.g.
+
+
+with System;
+with Ada.Containers.Synchronized_Queue_Interfaces;
+
+
+generic
+ with package Queue_Interfaces is
+ new Ada.Containers.Synchronized_Queue_Interfaces (<>);
+package Ada.Containers.Bounded_Synchronized_Queues is
+ pragma Preelaborate (Bounded_Synchronized_Queues);
+
+
+private
+ -- Declarations for private part of protected type
+end private;
+
+
+ protected
+ type Queue (Capacity : Count_Type;
+ Ceiling : System.Any_Priority) is
+ new Queue_Interfaces.Queue with
+ pragma Priority (Ceiling);
+
+
+ entry Enqueue (New_Item : Queue_Interfaces.Element_Type);
+ entry Dequeue (Element : out Queue_Interfaces.Element_Type);
+ function Current_Use return Count_Type;
+ function Peak_Use return Count_Type;
+ private
+ -- Uses previously declared types / instantiations / whatever
+ end Queue;
+
+
+end Ada.Containers.Bounded_Synchronized_Queues;
+
+****************************************************************
+
+From: Randy Brukardt
+Date: Tuesday, June 29, 2010 2:01 PM
+
+> Or...
+> ...resurrect (some form of) AI05-0074!!
+
+There are 4 very different alternatives in AI05-0074, and you are suggesting only a single one (AI05-0074-2). None of the others provide any sort of solution to this problem.
+
+Also note that this solution doesn't work, because the second visible part does not have visibility into the private part; that includes inside of the private part of the protected types. Recall that while child units have visibility into their parent's p
rivate part, that is not true for visible nested units.
+
+---
+
+In any case, please do not resurrect this historically bad idea, which breaks the model for Ada syntax (putting "end" and a semicolon) into the middle of a construct, and destroys the reading model of Ada specifications (that clients can stop reading when
they reach the "private" of the spec).
+The latter is also an important part of the implementation model of Ada compilers (especially when dealing with generic children).
+
+In addition, this construct does nothing to solve the actual problem that the series of AI05-0074-x proposals were trying to solve; a nested package works just as well (which is to say, not very well).
+
+****************************************************************
+
+From: Simon Wright
+Date: Tuesday, June 29, 2010 3:51 PM
+
+>(2) Add some junk private type(s) to the definition to be used in the private part of the protected objects (and for no other purpose). [This is my understanding of your suggestion.] But then, those type(s) have to be documented (what are they for? what
are the requirements on their streaming and equality operators? etc.). And that would be *very* limiting, as it would mean that the components could only have one particular design. (That would be completely inappropriate for the unbounded versions, and p
robably would be annoying even for the bounded versions as the implementation would be wildly different than the other containers.) There is no way this would even fly.
+
+Would this be so very bad?
+
+
+with System;
+generic
+ type Element_Type is private;
+package Queues is
+
+
+ type Representation_Type (Capacity : Positive) is limited private;
+
+
+ protected type Queue (Capacity : Positive;
+ Ceiling : System.Any_Priority) is
+
+
+ pragma Priority (Ceiling);
+
+
+ entry Enqueue (New_Item : Element_Type);
+ entry Dequeue (Element : out Element_Type);
+ function Current_Use return Natural;
+
+
+ private
+
+
+ Representation : Representation_Type (Capacity => Capacity);
+
+
+ end Queue;
+
+
+private
+
+
+ type Representation_Array
+ is array (Positive range <>) of Element_Type;
+
+
+ type Representation_Type (Capacity : Positive) is record
+ -- Something to indicate which parts of Contents are
+ -- occupied.
+ Contents : Representation_Array (1 .. Capacity);
+ end record;
+
+
+end Queues;
+
+****************************************************************
+
+From: Randy Brukardt
+Date: Tuesday, June 29, 2010 4:20 PM
+
+"Very Bad"? -- Probably not. But it is lousy Ada design (because the type Representation_Type has no purpose for the client, and indeed it would be dangerous to declare an object of that type), and one of the things we always try to do is have the Ada sta
ndard library be good examples of Ada usage. (Obviously, we don't always succeed: see Strings, Unbounded).
+
+In any case, it would need a detailed description of what it is for, what a default initialized object does, we'd have to consider whether it must stream, how "=" works, does it need finalization, and so on. Moreover, the intended implementation is comple
tely opaque (given that we don't give private parts in Ada). I suppose we could explain it in the AARM, but the causal reader of Ada will be completely mystified (as I was when I originally saw your suggestion - I had written a different initial response).
+
+Making the interface protected somehow and declaring an ordinary private type from seems like a less invasive solution to me (even thought we'll still need to use wording to explain the Ceiling priority - at least that would make sense). Both of the other
workable solutions are ugly and would require a lot of new wording.
+
+****************************************************************
+
+From: Simon Wright
+Date: Tuesday, June 29, 2010 11:43 PM
+
+Yes, I included a full implementation because I wanted to be sure that it would actually compile with the current language.
+
+Would there be any mileage in replacing my "type Representation_Type (Capacity : Positive) is limited private;" which is clearly much over-specified by (in italics) "Any types needed for the private part of protected type Queue.
+Not specified by the language."?
+
+****************************************************************
+
+From: Martin Dowie
+Date: Wednesday, June 30, 2010 2:49 AM
+
+"Any types" => "Any declarations".
+
+This seems like a reasonable compromise to me - without starting a brand new AI on 'private to the outside world but visible to all'.
+
+Perhaps the "Implementation Advice" could be to use a 'mangled' name that would not be legal Ada in client code? Non-standard additions to standard packages have been the bane of many a project...yes, I'm looking at you XD-Ada!!!
+
+****************************************************************
+
+From: Randy Brukardt
+Date: Wednesday, June 30, 2010 9:58 PM
+
+That would be a worse idea, because adding declarations to a language-defined package potentially causes incompatibilities. The effect of allowing random implementation-defined names in these packages is to reduce portability, even if the names aren't use
d by clients. (Names of types can make other things disappear via use-clause cancelation, if there is an identical name in some other package which is also "used".)
+
+That's why it is rare that the language allows the introduction of implementation-defined identifiers in language-defined packages. For instance, there have been several instances where allowing the addition of implementation-defined enumeration literals
to extend a language-defined enumeration type would have seemed reasonable. But that has been deemed a bad idea and thus has not been allowed.
+
+****************************************************************
+
+From: Bob Duff
+Date: Tuesday, July 6, 2010 10:21 AM
+
+> How are the queues expected to be implemented? e.g.
+>...
+> protected
+> type Queue (Capacity : Count_Type;
+>...
+> private
+> -- ******************************************************
+> -- Can't define an array type to hold the elements here
+> -- Can't use an anonymous array type
+> -- Can't instantiate a bounded container package
+
+Thanks for pointing out this serious flaw in the AI!
+I worked on this AI, and I'm embarrassed that I didn't notice it.
+
+Randy wrote:
+
+> The same would be true of the access types needed to implement the
+> root of the data structures for the unbounded forms - they can't be
+> written in the private part of the protected types either. (Anonymous
+> types can't be used, you need to be able to deallocate them.)
+
+That's a good point. Couldn't an anon access type be used, and converted back and forth to/from a named access type used for [de]allocation?
+
+But that doesn't really solve the problem. The real issue is that the implementer should have freedom to use whatever (correct) implementation they like without polluting the client's name space. Martin's comment "instantiate a bounded container" above
is relevant.
+
+> My initial reaction is to
+> completely give up and junk the entire thing.
+
+Well, we can't accuse Randy of being overly optimistic. ;-)
+
+Seriously, I'm not ready to junk it yet. Later Randy came up with this:
+
+> Perhaps we ought to add:
+> type Protected_Queue is protected interface and Queue; and then
+> derive the concrete types from Protected_Queue?? That would eliminate
+> the need for word for at least the requirement to implement as a
+> protected type. (We'd still have to add wording to require the ceiling
+> priority to be that of the Ceiling discriminant.)
+
+which is the best idea I've seen so far. Any fatal flaws in that?
+
+I think it's important that timed and conditional calls be allowed, which this solution provides.
+
+> In any case, this is very aggravating to do, as it will require
+> reverting the entire AI to the previous version and then trying to
+> apply the other changes back to it (the profiles of the routines being
+> so different that it isn't sensible to try to repair them all
+> individually; it took three iterations to get this set of protected changes right).
+
+Yes, it's aggravating, but if we can agree on the above solution (or some other), I'm willing to rewrite the AI. And I'm willing to try to get it right this time. ;-)
+
+>...And this is such a
+> major change that the entire thing will have to go back for another
+>vote, no way to treat this as a "typo"!!
+
+Agreed -- not a typo.
+
+> ...one of the things we
+> always try to do is have the Ada standard library be good examples of
+> Ada usage.
+
+True, but Ada has a flaw here: you can't declare hidden stuff to be used only in the private part of a protected or task type. We've always said, "Oh, well, it's not SO horrible to expose such stuff to clients, and put a comment
+'-- For internal use only'." But when it's language defined, it DOES seem horrible.
+
+Is there any support for fixing this flaw? E.g. make the private part of a package visible in the private part of a nested protected unit?
+Tricky to do, without incompatibilities and implementation problems rearing their ugly heads. I guess I don't recommend it.
+
+****************************************************************
+
+From: Bob Duff
+Date: Tuesday, July 6, 2010 10:24 AM
+
+> That would be a worse idea, because adding declarations to a
+> language-defined package potentially causes incompatibilities.
+
+I agree. Polluting the client's namespace is bad, polluting it with impl-def stuff is worse.
+
+>... The effect of
+> allowing random implementation-defined names in these packages is to
+>reduce portability, even if the names aren't used by clients. (Names
+>of types can make other things disappear via use-clause cancelation,
+>if there is an identical name in some other package which is also
+>"used".)
+>
+> That's way it is rare that the language allows the introduction of
+> implementation-defined identifiers in language-defined packages. For
+> instance, there have been several instances where allowing the
+> addition of implementation-defined enumeration literals to extend a
+> language-defined enumeration type would have seemed reasonable.
+
+Can you remind me of some such case(s)? I'm curious. Note that enum lits aren't as bad, since they are overloadable, and therefore less likely to cause portability problems.
+
+>... But that has been deemed a
+> bad idea and thus has not been allowed.
+
+****************************************************************
+
+From: Randy Brukardt
+Date: Tuesday, July 6, 2010 1:31 PM
+
+> > The same would be true of the access types needed to implement the
+> > root of the data structures for the unbounded forms - they can't be
+> > written in the private part of the protected types either. (Anonymous
+> > types can't be used, you need to be able to deallocate them.)
+>
+> That's a good point. Couldn't an anon access type be used, and
+> converted back and forth to/from a named access type used for
+> [de]allocation?
+
+The problem isn't so much with the access type as what it points at.
+Typically, that would be a node record of some sort, with an element object and some pointers to link nodes together. But there is no way to declare the node record.
+
+> But that doesn't really solve the problem. The real issue is that the
+> implementer should have freedom to use whatever
+> (correct) implementation they like without polluting the client's name
+> space. Martin's comment "instantiate a bounded container" above is
+> relevant.
+
+Right.
+
+****************************************************************
+
+From: Martin Dowie
+Date: Tuesday, July 6, 2010 11:43 AM
+
+I agree. Polluting the client's namespace is bad, polluting it
+with impl-def stuff is worse.
+
+
+
+It's only worse if it's a legal Ada name that clients can use...my suggestion is to advise using a 'mangled' name for such thing.
+
+
+I'e be a bit surprised if there are compilers out there that don't use/allow 'special' internal names anyway.
+
+p.s. Hmmm wonder if there is anything in that the two people saying "just add a declaration and say something about it being special" are users and those say "don't" are compiler writers... :-)
+
+****************************************************************
+
+From: Bob Duff
+Date: Tuesday, July 6, 2010 5:09 PM
+
+> It's only worse if it's a legal Ada name that clients can use...my
+> suggestion is to advise using a 'mangled' name for such thing.
+
+Ah, I see. I guess I didn't understand 'mangled' in this sense. So you mean a name that is not a legal Ada identifier, but that the compiler accepts given some special switch, right? Yes, that can easily work. It is somewhat unsatisfying, because the
intent of ARG is that all container packages should be implementable in pure standard Ada. Preferably Ada in "good style", as Randy noted earlier.
+
+There is of course no RM requirement that the predefined stuff be implemented in Ada. It could be "magic". But it's nice if it's implementable in Ada.
+
+> I'e be a bit surprised if there are compilers out there that don't
+> use/allow 'special' internal names anyway.
+
+GNAT doesn't do that. The compiler does generate 'special' internal names, to be fed to the back end and linker, but it doesn't allow them in source code.
+
+> p.s. Hmmm wonder if there is anything in that the two people saying
+> "just add a declaration and say something about it being special" are
+> users and those say "don't" are compiler writers... :-)
+
+Or language lawyers. ;-)
+
+****************************************************************
+
+From: Randy Brukardt
+Date: Tuesday, July 6, 2010 7:04 PM
+
+> GNAT doesn't do that. The compiler does generate 'special'
+> internal names, to be fed to the back end and linker, but it doesn't
+> allow them in source code.
+
+Janus/Ada doesn't have any special sort of identifier either. My theory always has been that if it can't be written in Ada, it isn't worth writing.
+(OK, that's not quite true, but we never saw any need for non-usable identifiers in source code. Link-time is a different story, as Bob noted.)
+
+So, Martin, don't be surprised, but those things probably don't exist in most compilers.
+
+****************************************************************
+
+From: Martin Dowie
+Date: Wednesday, July 7, 2010 8:29 AM
+
+I shall consider myself slightly surprised! :-)
+
+Randy: you mentioned in a (much) earlier post that you particularly didn't want "end private" - how about "not private"? No new keyword and the parsing is still ad you described. Kind of in keeping with existing Ada style too, eg 'not null'.
+
+ps sorry for all the typos, I'm on holiday and tapping this all out on a very small screen!
+
+****************************************************************
+
+From: Martin Dowie
+Date: Wednesday, July 7, 2010 8:33 AM
+
+> There is of course no RM requirement that the predefined stuff be implemented
+> in Ada. It could be "magic". But it's nice if it's implementable in Ada
+
+My guess is that users don't care about 'magic' - so long as it is a useful addition to the language that's making use of a feature. If 'magic' indicates a hole in the language (as this case seems to be) then it can always be fixed and the 'magic' removed
in a later language revision.
+
+****************************************************************
+
+From: Matthew Heaney
+Date: Wednesday, July 7, 2010 8:53 AM
+
+> Thanks for pointing out this serious flaw in the AI!
+> I worked on this AI, and I'm embarrassed that I didn't notice it.
+
+I don't understand any of this. The full view of the bounded queues type goes in the private part of the bounded queues spec. The partial view is a synchronized derivation from the abstract Queues type.
+
+I still don't see what the problem is. Ed S. posted the implementation in
+his last message. Here's what I have from an older draft of this AI:
+
+with Ada.Containers.Queues;
+
+generic
+ with package Queues is new Ada.Containers.Queues (<>);
+
+package Ada.Containers.Bounded_Queues is
+ pragma Pure;
+
+ type Queue (Capacity : Count_Type) is
+ synchronized new Queues.Queue with private;
+
+private
+
+ type Elements_Type is array (Count_Type range <>) of Queues.Element_Type;
+
+ protected type Queue (Capacity : Count_Type) is new Queues.Queue with
+
+ overriding
+ entry Enqueue (New_Item : Queues.Element_Type);
+
+ overriding
+ entry Dequeue (Element : out Queues.Element_Type);
+
+ overriding
+ function Is_Empty return Boolean;
+
+ overriding
+ function Is_Full return Boolean;
+
+ private
+
+ Elements : Elements_Type (1 .. Capacity);
+ First : Count_Type; -- applies only when queue not empty
+ Last : Count_Type := 0; -- queue is empty
+
+ end Queue;
+
+end Ada.Containers.Bounded_Queues;
+
+
+Why is Martin saying the full view of the implementation of type (bounded) Queue is in the public part of the spec? Since when do we ever expose the implementation of the type?
+
+****************************************************************
+
+From: Martin Dowie
+Date: Wednesday, July 7, 2010 9:44 AM
+
+That's an old proposal - check the latest revision for the new proposal. I think the problem was associating the priority with the type. With the 'old' proposal you need to say it in words - not in Ada (I think).
+
+****************************************************************
+
+From: Matthew Heaney
+Date: Wednesday, July 7, 2010 8:48 AM
+
+Ed had written:
+
+> type Queue (Capacity : Count_Type;
+> Ceiling : System.Any_Priority) is
+> new Queue_Interfaces.Queue with private;
+
+
+Don’t you need to say “synchronized new” or “protected new” here?
+
+
+>
+>...
+>private
+> -- whatever auxiliary types are needed.
+> protected
+> type Queue (Capacity : Count_Type;
+> Ceiling : System.Any_Priority) is
+> new Queue_Interfaces.Queue with
+> pragma Priority (Ceiling);
+>
+> ...
+>
+>end Ada.Containers.Bounded_Synchronized_Queues;
+
+Yes, agreed -- I had simply assumed that this was how the concrete type was declared.
+
+****************************************************************
+
+From: Randy Brukardt
+Date: Wednesday, July 7, 2010 11:15 AM
+
+> type Queue (Capacity : Count_Type;
+> Ceiling : System.Any_Priority) is
+> new Queue_Interfaces.Queue with private;
+>
+> Don't you need to say "synchronized new" or "protected new" here?
+
+You have to say "synchronized new". There is no "protected new".
+
+Which is the problem. We need to require that the implementation is a protected type, and we need to specify its ceiling priority is that of the discriminant. There is no way in the current language to do either for the private extension.
+
+It was pointed out that given that, there is no need for the private type, since a protected type has its own private part. But we missed the fact that you can't actually declare types in that private part, and it doesn't have visibility on private childr
en, so there is no way to hide the types used there.
+
+This is generally a problem with Ada protected types, one that we were not able to find a solution to because of the mess of additional operations that would have to appear inside of another type.
+
+> Yes, agreed -- I had simply assumed that this was how the concrete
+> type was declared.
+
+That was not the proposal; it would help if you actually read the AIs from time to time. :-)
+
+Requiring this to be the implementation is extremely ugly and lousy Ada style, but it appears we don't have much choice. One thing that would help is to create a protected interface (which then requires the implementation to be protected). Bob is planning
to rewrite the AI this way, if I understand the e-mail correctly.
+
+****************************************************************
+
+From: Bob Duff
+Date: Wednesday, July 7, 2010 12:20 PM
+
+> Bob is planning to rewrite the AI this way, if I understand the e-mail
+> correctly.
+
+If there's a consensus on the solution.
+
+****************************************************************
+
+From: Randy Brukardt
+Date: Wednesday, July 7, 2010 1:06 PM
+
+Is there any other viable alternative? I haven't heard one.
+
+****************************************************************
+
+From: Bob Duff
+Date: Wednesday, July 7, 2010 1:48 PM
+
+> Is there any other viable alternative? I haven't heard one.
+
+Well, some people have suggested that compiler magic is viable.
+That is, the compiler processes predefined units in a special mode that allows normally-illegal identifiers, thus avoiding polluting the client's namespace.
+
+I don't much like that solution, but it's certainly easy to implement.
+
+****************************************************************
+
+From: Simon Wright
+Date: Wednesday, July 7, 2010 2:08 PM
+
+As I understand it, the idea is that the standard should say something like "declarations necessary to implement the private part of the protected type, not defined by the language" with implementation advice that measures should be taken to ensure that s
uch declarations aren't available to users of the package.
+
+If that was the case, then instead of mangling names an implementation might choose to use an implementation-defined pragma, eg Package_Visibility_Only, to make this happen.
+
+****************************************************************
+
+From: Randy Brukardt
+Date: Wednesday, July 7, 2010 2:15 PM
+
+> I don't much like that solution, but it's certainly easy to implement.
+
+That seems completely bogus as a "solution" to me; we've never required that in any other case for the specifications of Ada predefined units, and it seems bad to start now. If Ada isn't powerful enough to describe some packages, the solution is to fix Ad
a, not require implementers to create some sort of hack.
+
+****************************************************************
+
+From: Randy Brukardt
+Date: Wednesday, July 7, 2010 3:00 PM
+
+> If that was the case, then instead of mangling names an implementation
+> might choose to use an implementation-defined pragma, eg
+> Package_Visibility_Only, to make this happen.
+
+No Ada implementer is going to fiddle with the extremely delicate visibility machinery if any easier solution is available. And pragmas are particularly annoying when they change the properties of some declaration, because they come after the declaration
and that generally means having to alter the declaration after the fact (with all of the complications of freezing rules in order to avoid problems). It's way more machinery than the problem is worth, especially when a relatively simple solution (allowing
'$' in identifiers, for instance) is available.
+
+So this is a long-winded way to say the same thing.
+
+Also note that Implementation Advice (which implementers are allowed to ignore, and commonly do) is not strong enough here. The implementation shall not pollute the client's namespace, ever -- this is *not* Advice, it would have to be a Requirement.
+
+The point is, that this would save nothing over the private type solution.
+The reason for avoiding that solution was to reduce the amount of English text needed. If we have to put in a number of Implementation Permissions and Implementation Requirements to allow these extra declarations, we've gained nothing over simply having a
n Implementation Requirement that the private type be implemented with a protected type with a ceiling priority of Ceiling. The latter is probably shorter and does not require compiler magic.
+
+Given two equal length alternatives, one that requires compiler magic and one that does not, we've be insane to chose the one requiring magic. Which is why I don't understand why we're even discussing this...
+
+****************************************************************
+
+From: Bob Duff
+Date: Wednesday, July 7, 2010 3:45 PM
+
+> As I understand it, the idea is that the standard should say something
+> like "declarations necessary to implement the private part of the
+> protected type, not defined by the language" with implementation
+> advice that measures should be taken to ensure that such declarations
+> aren't available to users of the package.
+>
+> If that was the case, then instead of mangling names an implementation
+> might choose to use an implementation-defined pragma, eg
+> Package_Visibility_Only, to make this happen.
+
+If that's the desired solution, then no RM verbiage is needed. Compilers are always allowed to use magic to implement predefined stuff. And they are required to avoid polluting the client's namespace (as Randy said, that's not mere "Advice"). Any such
verbiage would belong in the AARM.
+
+The easiest such magic is to allow syntactically illegal identifiers in a special mode. But pragmas could work, too -- that's just harder to implement.
+
+But I agree with Randy that it is undesirable to require the use of magic to implement these queue packages.
+
+****************************************************************
+
+From: Bob Duff
+Date: Wednesday, July 7, 2010 3:53 PM
+
+> That seems completely bogus as a "solution" to me; ...
+
+I agree it's undesirable (maybe not quite "completely bogus").
+
+>...we've never required that
+> in any other case for the specifications of Ada predefined units, ...
+
+Well, magic is required to implement type Wide_Wide_Character. ;-)
+
+>...and it
+> seems bad to start now. If Ada isn't powerful enough to describe some
+>packages, the solution is to fix Ada, not require implementers to
+>create some sort of hack.
+
+To me, "fix Ada" would mean "provide a mechanism for declaring the necessary types such that they are visible in the private part of the protected type, but not visible to clients". Users have definitely complained about the lack of such a feature.
+
+But I think that would require major surgery to the language, and also to implementations, so I'm not in favor of that.
+
+Historical note: I think Tucker's original Ada 9X proposal involved a solution to this problem.
+
+****************************************************************
+
+From: Randy Brukardt
+Date: Wednesday, July 7, 2010 4:15 PM
+
+...
+> >...we've never required that
+> > in any other case for the specifications of Ada predefined units, ...
+>
+> Well, magic is required to implement type Wide_Wide_Character. ;-)
+
+I don't see that. Character literals are part of the language, no magic there. And whatever is in the compiler's symboltable is irrelevant, given that users can't see it (one could consider anything there "magic" if you want).
+
+You probably do need magic to implement Wide_Wide_Character'Image and 'Value (else the needed table gets really large), but there again exactly how such things are represented is really implementation-defined and irrelevant clients.
+
+So I think we need a better definition of "magic" to settle this. I would argue that it is some feature that is visible to clients that they cannot implement/use themselves. By that definition, all uses of 'Image are magic.
+
+> >...and it
+> > seems bad to start now. If Ada isn't powerful enough to describe
+> >some packages, the solution is to fix Ada, not require implementers
+> >to create some sort of hack.
+>
+> To me, "fix Ada" would mean "provide a mechanism for declaring the
+> necessary types such that they are visible in the private part of the
+> protected type, but not visible to clients". Users have definitely
+> complained about the lack of such a feature.
+>
+> But I think that would require major surgery to the language, and also
+> to implementations, so I'm not in favor of that.
+
+I agree, especially at this late point.
+
+But by "fix Ada", I also meant to include "changing the (predefined) packages such that the problem is eliminated". After all, Ada doesn't allow you to write every possible program in every possible way; sometimes some restructuring is needed to get a goo
d solution. Just because restructuring is needed doesn't mean that Ada is broken.
+
+I'm more concerned about the lack of "protected" and "task" as possibilities in private types. It seems strange to me that you can require a private type to be implemented by a limited or synchronized type, but you can't be more specific than that even th
ough there are massive differences in active and passive implementations (and it is commonly the case that one or the other will not work properly, especially if priorities matter). If we could define a protected private extension, we'd only need one addit
ional sentence of English (to describe the priority), which seems OK to me. I suggested using a protected interface as a workaround for this omission, but that also clutters the name-space a bit.
+
+****************************************************************
+
+From: Bob Duff
+Date: Wednesday, July 7, 2010 4:47 PM
+
+> I don't see that. Character literals are part of the language, no
+> magic there.
+
+I meant that it is impractical to type in the text of package Standard, with all 2**31 or however many characters are in Wide_Wide_Character.
+
+Also, the control characters are written in italics to indicate that they're not real identifiers.
+
+GNAT concocts the Standard symbol table out of whole cloth, rather than compiling some psuedo source text.
+
+...
+> So I think we need a better definition of "magic" to settle this.
+
+Well, we don't really need to settle it, since we both agree that requiring magic for the queues packages is a bad idea.
+
+My definition of "magic" is anything that's not written in pure standard Ada. There's lots of magic required in predefined package BODIES, but we try to keep it out of visible parts.
+
+...
+> But by "fix Ada", I also meant to include "changing the (predefined)
+> packages such that the problem is eliminated". After all, Ada doesn't
+> allow you to write every possible program in every possible way;
+> sometimes some restructuring is needed to get a good solution. Just
+> because restructuring is needed doesn't mean that Ada is broken.
+
+OK.
+
+> I'm more concerned about the lack of "protected" and "task" as
+> possibilities in private types. It seems strange to me that you can
+> require a private type to be implemented by a limited or synchronized
+> type, but you can't be more specific than that even though there are
+> massive differences in active and passive implementations (and it is
+> commonly the case that one or the other will not work properly,
+> especially if priorities matter). If we could define a protected
+> private extension, we'd only need one additional sentence of English
+> (to describe the priority), which seems OK to me. I suggested using a
+> protected interface as a workaround for this omission, but that also clutters the name-space a bit.
+
+If the clutter is standard, then it's not a big problem.
+
+****************************************************************
+
+From: Randy Brukardt
+Date: Thursday, August 5, 2010 7:21 PM
+
+> To me, "fix Ada" would mean "provide a mechanism for declaring the
+> necessary types such that they are visible in the private part of the
+> protected type, but not visible to clients". Users have definitely
+> complained about the lack of such a feature.
+>
+> But I think that would require major surgery to the language, and also
+> to implementations, so I'm not in favor of that.
+
+Interestingly, I've been thinking about this, and I've concluded its not that bad (although I may have forgotten some Baird-cases). More importantly, it's better than the alternatives that we previously discussed, which all require some form of name-space
pollution and (in most cases) loss of readability.
+
+I mistakenly spent all day yesterday formatting the current version of
+AI05-159-1 for the Standard, having forgotten about this thread. When I remembered it this morning, I was very annoyed. I then tried to figure out what the change would have to be, and realized that virtually all of them are in fact illegal for one reason
or another.
+
+But let me refresh everyone as to what the problem was. The proposed specification for Unbounded_Synchronized_Queues is as follows:
+
+with System;
+with Ada.Containers.Synchronized_Queue_Interfaces;
+generic
+ with package Queue_Interfaces is new
+Ada.Containers.Synchronized_Queue_Interfaces (<>);
+ Default_Ceiling: System.Any_Priority := System.Priority'Last; package Ada.Containers.Unbounded_Synchronized_Queues is
+ pragma Preelaborate(Unbounded_Synchronized_Queues);
+
+ protected type Queue
+ (Capacity : Count_Type := Default_Capacity;
+ Ceiling: System.Any_Priority := Default_Ceiling) is
+ new Queue_Interfaces.Queue with
+ pragma Priority(Ceiling);
+
+ overriding
+ entry Enqueue (New_Item: in Queue_Interfaces.Element_Type);
+ overriding
+ entry Dequeue (Element: out Queue_Interfaces.Element_Type);
+
+ overriding
+ function Current_Use return Count_Type;
+ overriding
+ function Peak_Use return Count_Type;
+
+ private
+ ... -- not specified by the language
+ end Queue;
+
+private
+
+ ... -- not specified by the language
+
+end Ada.Containers.Unbounded_Synchronized_Queues;
+
+Martin Dowie pointed out that this isn't implementable, because there is nowhere to define the "helper" types needed to implement the protected queue. For the bounded forms, this would be (at least) an array of elements; for the unbounded forms, this woul
d be (at least) some sort of queue node [we can use anonymous access types for the pointers, but the node will need a record]. This is a problem because types are not allowed to be declared in the private part of a protected type, and there is nowhere else
to put them that would have the appropriate visibility (there is no visibility into the private part of a formal package, for instance, and the private part of this package is too late).
+
+The easiest fix is to add
+
+ type Queue_Implementation_Type is private;
+
+before protected type Queue. This type could be completed by whatever the implementer needed, and with sufficient cleverness, would suffice for virtually any possible data structure. We would have to add some wording to explain it (this is used to impleme
nt the queue and should be ignored by users), and that is ugly. It also adds some name pollution to the user's name space (which can be minimized by selecting a name that could never conflict with anything real:
+
+ type Queue_Implementation_Type_Do_Not_Use_In_Client_Code is private;
+
+Because this was so ugly, we pretty much decided to revert to a private version of the type. We proposed adding
+
+ type Protected_Queue is protected interface and Queue;
+
+to the interface package, and then revising the package to look like:
+
+with System;
+with Ada.Containers.Synchronized_Queue_Interfaces;
+generic
+ with package Queue_Interfaces is new
+Ada.Containers.Synchronized_Queue_Interfaces (<>);
+ Default_Ceiling: System.Any_Priority := System.Priority'Last; package Ada.Containers.Unbounded_Synchronized_Queues is
+ pragma Preelaborate(Unbounded_Synchronized_Queues);
+
+ type Queue
+ (Capacity : Count_Type := Default_Capacity;
+ Ceiling: System.Any_Priority := Default_Ceiling) is
+ synchronized new Queue_Interfaces.Protected_Queue with private;
+
+ overriding
+ procedure Enqueue
+ (Container : in out Queue;
+ New_Item : in Element_Type);
+
+ overriding
+ procedure Dequeue
+ (Container : in out Queue;
+ Element : out Element_Type);
+
+ overriding
+ function Current_Use (Container : Queue) return Count_Type;
+
+ overriding
+ function Peak_Use (Container : Queue) return Count_Type;
+
+private
+
+ ... -- not specified by the language
+
+end Ada.Containers.Unbounded_Synchronized_Queues;
+
+However, this structure also cannot be implemented, at least with the rules of Ada as they are today. There are two problems. First, the declaration of procedure Enqueue and Dequeue are illegal, because they are not entries, and the original declaration h
as pragma Implemented (By_Entry). We could fix that by putting the pragma on these declarations as well, or by changing the rules for pragma Implemented.
+
+But the big problem is the second one: there is no way to complete these procedure declarations with an entry. We presume a protected type like the original type Queue is given in the private part. That would have the appropriate entries, but there is no
way to connect them to these explicit declarations. That's because the entire "implemented by" mechanism is defined to *override* inherited routines, not to *complete* explicit routines. Indeed, 9.4(11.4/3) makes the declaration of subprograms like Dequeue
these *illegal* because of the conflict.
+
+We could try to fix this, but it would be an earthquake in the language definition (pretty much the entire model would have to be blown up and done over more generally). I suspect the implementation changes wouldn't be as bad (there isn't much difference
between an inherited routine and an explicitly declared specification of a routine), but it would take forever to get the bugs out of any major standard rewrite (it's not clear that we've gotten all of the bugs out of the current model!).
+
+We can fix this problem by omitting the declarations of subprograms altogether, since the language does allow overriding abstract routines in the private part (and there the "implemented by" would be in place of overriding, which is OK). That would make t
he specification look like:
+
+with System;
+with Ada.Containers.Synchronized_Queue_Interfaces;
+generic
+ with package Queue_Interfaces is new
+Ada.Containers.Synchronized_Queue_Interfaces (<>);
+ Default_Ceiling: System.Any_Priority := System.Priority'Last; package Ada.Containers.Unbounded_Synchronized_Queues is
+ pragma Preelaborate(Unbounded_Synchronized_Queues);
+
+ type Queue
+ (Capacity : Count_Type := Default_Capacity;
+ Ceiling: System.Any_Priority := Default_Ceiling) is
+ synchronized new Queue_Interfaces.Protected_Queue with private;
+
+private
+
+ ... -- not specified by the language
+
+end Ada.Containers.Unbounded_Synchronized_Queues;
+
+While this is legal, we've lost all readability.
+
+One of the big advantages of the original design is that while we had interfaces involved, you could completely ignore them unless you wanted to use them. But this this structure, everyone has to understand how interfaces inherit operations in order to ha
ve any idea of what is going on. I would guess that 98% of Ada programmers would be completely mystified by this specification!
+
+We could of course put the inherited declarations into comments or into text in order to reduce this problem, but that is ugly and not necessarily any less confusing. (It might help the 25% of Ada programmers that have some understanding of derivation and
/or OOP, but the rest will still be lost.)
+
+The priority queues make this into an even worse problem. As you may recall, the priority queues have an additional operation that is not inherited. This operation is also supposed to be implemented by an entry, so just adding:
+
+ procedure Dequeue_Only_High_Priority
+ (Container : in out Queue;
+ Low_Priority : in Queue_Priority;
+ Element : out Queue_Interfaces.Element_Type);
+
+to the above specification just brings up the same set of problems as the original private specification.
+
+The only way that this can be solved is to add yet another interface that has this operation:
+
+ type Protected_Priority_Queue is protected interface and Queue;
+
+ procedure Dequeue_Only_High_Priority
+ (Container : in out Protected_Priority_Queue;
+ Low_Priority : in Queue_Priority;
+ Element : out Queue_Interfaces.Element_Type) is abstract;
+
+Note that this solution also has a name-space pollution problem, because here we've added two interfaces that we didn't really need.
+
+--------
+
+Finding neither of these solutions very palatable, I decided to look back at the original problem. It's unnatural to try to hide a protected type in the private part; such types are by their nature private (anything you want to hide can be hidden in the p
rivate part of the type) and given that we want to insist that it is implemented by a protected type (which is almost always the case for such interfaces, especially if priorities are to be supported meaningfully), it makes no sense to try hide the type.
+
+So the original specifications are preferable. So what could we do to allow the original specifications to be implementable? After all, the inability to declare types in a protected type's private part has been a long-standing headache.
+
+The main reason for not allowing types inside of other types is that nesting of type declarations causes various semantic problems (mostly having to do with "additional operations"). But in thinking about this, I don't think this case is anything like the
cases that we've previously worried about (as in record types), as a protected type is a unit with its own visibility. So I wonder if this limitation could be lifted (or partially lifted) without any major problems. I'll explore that in my next message.
+
+****************************************************************
+
+From: Randy Brukardt
+Date: Thursday, August 5, 2010 8:14 PM
+
+As noted in my previous message, the Queue containers could be implemented
+directly if we allowed (some) type declarations in the private part of a
+protected type. We would need to allow at a minimum array types, untagged record
+types, and access types.
+
+The idea of allowing anonymous array types in record components has been
+explored in the past. Allowing that brings up various problems, mostly because
+the location of the declaration of the predefined operators is not well-defined.
+(Unfortunately, I haven't been able to find any discussion of this problem in
+the AARM or in any Rationale, so I'm not sure exactly what the problem is.)
+
+[Note that allowing anonymous array types alone would not be enough to make
+these packages implementable, it's just an example.]
+
+Generally, we've considered record types and protected types as similar. As
+such, since we can't allow this for record types, we've not even considered it
+for protected types. But in actuality, there isn't much in common between record
+and protected types:
+* A protected type is a unit, with a separate private part and body; a record is
+ completely visible;
+* A protected type only allows declaring private components; a record only
+ allows visible components;
+* A consequence of the previous is that a protected type does not allow an
+ aggregate naming any components, nor is there any other way to name components
+ outside of the protected type.
+
+These differences mean that any type declared in the private part of a protected
+type could only be visible in that protected part and the body of the protected
+type. That also extends to any predefined or inherited operations. Thus, if
+there are any anomalies, they would have to be limited to the protected type
+itself.
+
+One clear area of confusion would be whether exclusion would apply to any
+primitive routines. Note that there cannot be any new primitive subprograms
+(those can only exist in a package specification, which this is not), but new
+routines could be created via overriding. Routines declared within a protected
+type have a different profile (with an implicit PO parameter), which complicates
+overriding as well. But this is easily solved by simply not allowing any
+overriding of primitive operations for any type declared within a protected
+object.
+
+Once we've banned overriding, it's clear that tagged types have become useless
+(there can be no useful dispatching, and derivation does nothing but create a
+new tag), so we could simply ban them rather than try to figure out the
+implications.
+
+We surely don't want to add new kinds of unit nesting, so we also would ban type
+and protected types.
+
+Existing rules prevent the outer protected type itself from appearing in one of
+these declarations (other than as the designated type of an access type).
+
+What else could happen? It would be possible for "additional operations" to be
+declared at the start of the protected body. That doesn't seem to cause any
+hardship beyond what "additional operations" already do. There isn't any way for
+them to appear anywhere else (it's not possible to change the outer visibility
+while inside of the protected type).
+
+So it appears to me that a couple of additional rules would allow useful
+untagged type declarations within the private part and body of a protected type.
+
+In order to give Steve something to chew on, here is a concrete proposal.
+(Note: I think we would want to also allow anonymous array types here, in order
+to be consistent, but I didn't attempt to work out what was needed to do that.)
+
+-------------
+
+Modify 9.4(6) to:
+
+protected_element_declaration ::= protected_operation_declaration
+ | component_declaration
+ | type_declaration
+ | subtype_declaration
+
+Modify 9.4(8/1) to:
+
+protected_operation_item ::= subprogram_declaration
+ | subprogram_body
+ | entry_body
+ | aspect_clause
+ | type_declaration
+ | subtype_declaration
+
+Add after 9.4(11.13/2): [Legality Rules]
+
+A type_declaration that appears in a protected_element_declaration or a
+protected_operation_item shall not be for a tagged, protected, or task type.
+
+No subprogram shall override an inherited or predefined operation of the type
+declared by a type_declaration that appears in a protected_element_declaration
+or a protected_operation_item.
+
+------------
+
+Note that I added subtypes as well; I can't think of any problem with them.
+
+Do we need to say that any inherited or predefined operation of the type
+declared by a type_declaration that appears in a protected_element_declaration
+or a protected_operation_item does not have any special exclusion properties? I
+don't think so, given that it is an internal operation that can only be called
+from some other existing operation.
+
+How bad is the implementation of this? If the compiler represents a protected
+type as a unit in its symbol table, I would be surprised if there is a
+significant hardship to implement the visibility needed: it is just more
+declarations in a scope. Code needed would be limited; the main effect would be
+on finalization (as controlled components could be used in a record or array
+type, and access type collections might have to be finalized). I don't want to
+predict how bad that would be for other implementations, as they vary so much on
+this part. But compilers already have to deal with controlled components in
+protected types, so additional kinds of finalization at least have a clear place
+to be added.
+
+All-in-all, this would appear to be a big win for the usability of Ada (assuming
+no Steve Baird showstoppers...). It is more complex than just restructuring the
+Queue packages yet again, but it also fixes a long-standing Ada complaint. So I
+guess I'd like a serious look at it.
+
+****************************************************************
Questions? Ask the ACAA Technical Agent