!standard 8.2(11) 14-05-25 AI12-0003-1/05 !standard 13.11.3(3.1/3) !standard 13.11.3(4.1/3) !standard 13.11.3(4.2/3) !standard 13.11.3(6.2/3) !class Amendment 11-06-19 !status work item 11-06-19 !status received 11-03-21 !priority Low !difficulty Medium !subject Default storage pool for storage pools !summary The standard storage pool can be specified in a Default_Storage_Pool pragma. !problem If a programmer wants to specify the default storage pool as NULL through a configuration pragma, then how would one provide a user defined storage pool that does allocate a block of memory from the heap? !proposal Add a new argument to the Default_Storage_Pool pragma to achieve the effect of returning to the "standard" allocation method used by the implementation, usually the use of a general heap. [Editor's note: With this approach, this AI could be reclassified as a Binding Interpretation. Thus allowing the capability to be used immediately.] !wording Append after 8.2(11) (i.e., as a new paragraph at the end of the static semantics section): The immediate scope of a pragma which is not used as a configuration pragma is defined to be the region extending from immediately after the pragma to end of the pragma's nearest enclosing declarative region. Modify 13.11.3(3.1/3): storage_pool_indicator ::= storage_pool_name | null {| Standard} Modify 13.11.3 (4.1/3): If the pragma is used as a configuration pragma, the storage_pool_indicator shall be {either} null {or Standard}, and it defines the default pool to be {respectively} null {or Standard} within all applicable compilation units (see 10.1.5), except within the immediate scope of another pragma Default_Storage_Pool. Otherwise, [the pragma occurs immediately within a sequence of declarations, and] it defines the default pool within the immediate scope of the pragma to be either null{, Standard,} or the pool denoted by the storage_pool_name, except within the immediate scope of a later pragma Default_Storage_Pool. Redundant [Thus, an inner pragma overrides an outer one.] Add after 13.11.3 (4.1/3): Except within the immediate scope of another Default_Storage_Pool pragma, the Standard storage_pool_indicator causes the storage pool of any access type to be the standard storage pool as described in 13.11. <<< AI Note: the wording carefully ties into 13.11, so that it works for instances. >>>> Add after 13.11.3(4.2/3): The Standard storage_pool_indicator is an identifier specific to a pragma (see 2.8) and does not denote any declaration. AARM Ramification: The standard storage pool is not an object of the Standard package and is not restricted to having Preelaborable_Initialization. AARM Reason: The Standard storage_pool_indicator does not resolve to the package Standard as it is an identifier specific to a pragma. Resolving to package Standard would imply that the standard pool is an object declared in that package. A storage pool object however must be a variable (see 13.11), yet preelaborable packages depend on package Standard, which would require implementers to implement the standard storage pool with Preelaborable_Initialization, which is an unnecessary restriction. Modify 13.11.3(6.2/3): If the default pool is {neither} [non]null {nor Standard}, the Storage_Pool attribute is that pool. !discussion We do not want to give the standard storage pool a name, since it should remain implementation-defined whether, in the absence of user-provided storage pools, the storage pool model is used by the implementation at all. Specifically it might just go for the heap, or have a clever way of combining a general heap with pools of cached, equally-sized memory blocks. Specifically it might just go for the heap, or have a clever way of combining a general heap with pools of cached, equally-sized memory blocks. Extending the Default_Storage_Pool pragma to allow it to cause the implementation to revert to the standard allocation method seemed best to achieve the desired capability. !ACATS test An ACATS C-Test should be constructed to test this capability. !appendix From: Brad Moore Sent: Monday, March 21, 2011 8:22 AM AI05-0190-1 allows the default storage pool to be specified by a pragma. To implement an unbounded storage pool type, the first approach that comes to mind involves deriving a type from Root_Storage_Pool and allocating a block of memory from the heap and then doling objects from that block of memory. If a programmer wants to specify the default storage pool as NULL through a configuration pragma, then how would one provide a user defined storage pool that does allocate a block of memory from the heap? Is it the intent that such a configuration pragma enforces only static or stack based storage pools, and rules out any storage pools that allocate from the heap? Or does there need to be some implementation defined magic storage pool that does heap allocation, that can be named? Or should a storage pool object be exempt from the configuration pragma? with System.Storage_Pools; with System.Storage_Elements; package User_Defined_Pool is type My_Pool is new System.Storage_Pools.Root_Storage_Pool with private; ... private type Storage_Array_Access is access System.Storage_Elements.Storage_Array; for Storage_Array_Access'Storage_Pool use ???; -- What heap based storage pool can be used for this if the default is NULL? type My_Pool is new System.Storage_Pools.Root_Storage_Pool with record buffer : Storage_Array_Access; end record; overriding procedure Initialize (Item : in out My_Pool); end User_Defined_Pool; package body User_Defined_Pool is ... overriding procedure Initialize (Pool : in out My_Pool) is begin Pool.Buffer := new Ada.Storage_Elements.Storage_Array (1 .. 1_000_000); end Initialize; end User_Defined_Pool; Configuration pragma Default_Storage_Pool (Null); **************************************************************** From: Gary Dismukes Sent: Monday, March 21, 2011 1:37 PM > Is it the intent that such a configuration pragma enforces only static > or stack based storage pools, and rules out any storage pools that allocate from the heap? As I understand it, the intent is that it rules out the use of any default storage pools. > Or does there need to be some implementation defined magic storage > pool that does heap allocation, that can be named? If you need heap-based allocation in the presence of "null", then yes, I think you'd need to use an implementation-defined storage pool (such as the global storage pool that GNAT provides). > Or should a storage pool object be exempt from the configuration pragma? Not completely sure what you mean, but if the storage pool object itself needs to be allocated and managed within a storage pool, then I believe that that latter storage pool can't be a default storage pool (unless the storage pool you're talking about is outside the scope of the null). At least that's how understand the proposal. Bob might have some further comments here... **************************************************************** From: Bob Duff Sent: Monday, March 21, 2011 7:35 PM > If a programmer wants to specify the default storage pool as NULL > through a configuration pragma, then how would one provide a user > defined storage pool that does allocate a block of memory from the heap? Good question! I have suggested several times that there should be some way to denote "the default storage pool", or "the global heap", or whatever. Some people (in particular, Randy and Steve, I think) objected to that, because it's unimplementable on compilers that by default separate "collections" into different pools. But I still don't see why it's unimplementable. Every implementation has some sort of global heap, and could return that. It really doesn't matter if the implementation wants to use local pools for some types, or whatever. > Is it the intent that such a configuration pragma enforces only static > or stack based storage pools, and rules out any storage pools that > allocate from the heap? No. The intent is that you say "null" in a global config pragma, and that you can then use whatever sort of pools you like for particular access types. (And for the new "new" syntax.) I don't know if this discussion is "too late". In any case, you can always interface with VirtualAlloc on windows and mmap or malloc on Unix. But it would be nice to have a portable way of saying "I want the most-global pool, the one that interfaces with the operating system (if there is one)". **************************************************************** From: Randy Brukardt Sent: Monday, March 21, 2011 9:45 PM ... > I have suggested several times that there should be some way to denote > "the default storage pool", or "the global heap", or whatever. > Some people (in particular, Randy and Steve, I think) objected to > that, because it's unimplementable on compilers that by default > separate "collections" into different pools. That's a misunderstanding of my position. I agree that it would be valuable to have some sort of named default storage pool. But that idea has been discussed to death and nothing significant about it has changed since it was discussed. Thus I oppose discussing it again; if the result was any different this time, that would happen simply because the membership of the ARG has changed and I don't think that is a good reason for making such a change. In any case, I'd rather spend the time on topics that have a better chance of success. The AI in question was AI95-00300-1. I suggest looking at the minutes of the Vienna meeting (June 2020), the meeting in which that AI was discussed (there is not much in the AI itself; perhaps the mail on this was stored in AI95-00299-1, which is related). Humm: since that was the only meeting at which that AI was considered and that was the "heat stroke" meeting (at which many decisions proved to be silly, probably from trying to work in rooms that resembled the interior of a furnace - outside air temps were 34-36 C during the meeting, and we met in unair-conditioned rooms), perhaps I can be convinced to reconsider. But we need a solid proposal (we've never had one). And in any case it is too late for this go round. **************************************************************** From: Jean-Pierre Rosen Sent: Tuesday, March 22, 2011 12:49 PM > Humm: since that was the only meeting at which that AI was considered > and that was the "heat stroke" meeting (at which many decisions proved > to be silly, probably from trying to work in rooms that resembled the > interior of a furnace - outside air temps were 34-36 C during the > meeting, and we met in unair-conditioned rooms), perhaps I can be > convinced to reconsider. But we need a solid proposal (we've never had > one). And in any case it is too late for this go round. Not really. Nothing prevents any implementation from providing such a pool; therefore, even if it's too late for the standard, deciding how it should be done could help all implementations of Ada 2012 do the same thing (slightly tongue-in-cheek about "all implementations of Ada 2012"). **************************************************************** From: Randy Brukardt Sent: Tuesday, March 22, 2011 3:57 PM You're just repeating my point: it is too late for this standard. We could talk about ideas for the next standard (which might get implemented early), but right now our only goal should be to finish *this* standard. We still have important issues to resolve, and spending any significant effort on other issues right now is counter-productive. (I spent roughly one hour per 30 or so messages of each e-mail discussion, although of course this value varies wildly.) This is the same reason that we're not working on ASIS right now. This isn't going to be a long delay on such discussions; it makes perfect sense to start thinking of the future once we get past the NB review of the standard (hopefully in the June/July time-frame). Until then, however, let's keep our collective nose to the grindstone. **************************************************************** From: Bob Duff Sent: Tuesday, March 22, 2011 4:29 PM > The AI in question was AI95-00300-1. I suggest looking at the minutes > of the Vienna meeting (June 2020), the meeting in which that AI was > discussed (there is not much in the AI itself; perhaps the mail on > this was stored in AI95-00299-1, which is related). I'd call that 20/20 foresight. Do we really have a meeting scheduled for Vienna in 2020? And have you really already finished the minutes? Wow! ;-) Seriously, it was meeting #16, in June 2002. I looked at AI95-00300, AI95-00299, and the minutes for both. 300 is addressing a somewhat different issue than what I had in mind. In any case, it is seriously flawed in several ways. Thanks for the historical info, anyway. > Humm: since that was the only meeting at which that AI was considered > and that was the "heat stroke" meeting (at which many decisions proved > to be silly, probably from trying to work in rooms that resembled the > interior of a furnace - outside air temps were 34-36 C during the > meeting, and we met in unair-conditioned rooms), perhaps I can be > convinced to reconsider. But we need a solid proposal (we've never had > one). And in any case it is too late for this go round. I don't know if it was heat stroke, but the minutes show that ARG misunderstood the 300 proposal. But never mind -- I'm not trying to revive it! **************************************************************** From: Tucker Taft Sent: Saturday, June 25, 2011 6:11 AM GNAT "standard" storage pools: [excerpt from GNAT documentation] 22.1 Some Useful Memory Pools The System.Pool_Global package offers the Unbounded_No_Reclaim_Pool storage pool. Allocations use the standard system call malloc while deallocations use the standard system call free. No reclamation is performed when the pool goes out of scope. For performance reasons, the standard default Ada allocators/deallocators do not use any explicit storage pools but if they did, they could use this storage pool without any change in behavior. That is why this storage pool is used when the user manages to make the default implicit allocator explicit as in this example: type T1 is access Something; -- no Storage pool is defined for T2 type T2 is access Something_Else; for T2'Storage_Pool use T1'Storage_Pool; -- the above is equivalent to for T2'Storage_Pool use System.Pool_Global.Global_Pool_Object; The System.Pool_Local package offers the Unbounded_Reclaim_Pool storage pool. The allocation strategy is similar to Pool_Local's except that the all storage allocated with this pool is reclaimed when the pool object goes out of scope. This pool provides a explicit mechanism similar to the implicit one provided by several Ada 83 compilers for allocations performed through a local access type and whose purpose was to reclaim memory when exiting the scope of a given local access. As an example, the following program does not leak memory even though it does not perform explicit deallocation: with System.Pool_Local; procedure Pooloc1 is procedure Internal is type A is access Integer; X : System.Pool_Local.Unbounded_Reclaim_Pool; for A'Storage_Pool use X; v : A; begin for I in 1 .. 50 loop v := new Integer; end loop; end Internal; begin for I in 1 .. 100 loop Internal; end loop; end Pooloc1; The System.Pool_Size package implements the Stack_Bounded_Pool used when Storage_Size is specified for an access type. The whole storage for the pool is allocated at once, usually on the stack at the point where the access type is elaborated. It is automatically reclaimed when exiting the scope where the access type is defined. This package is not intended to be used directly by the user and it is implicitly used for each such declaration: type T1 is access Something; for T1'Storage_Size use 10_000; **************************************************************** From: Randy Brukardt Sent: Saturday, December 1, 2012 3:01 PM [Commenting on version /02 of this AI.] <<<<<< Aside 2: This issue of contradictory pragmas surely is not limited to the storage pool pragmas. 2a) has anybody checked the manual for problems with other pragmas. 2b) shouldn't this be a general rule on configuration pragmas? >>>>> If you're not careful, there will be an action item in your future!! :-) :-) To actually answer your question, I know that we spent quite a bit of time looking at this issue for Suppress and Unsuppress. So if some generalish solution is adopted, you'd have to be careful to ensure that it didn't apply to them (or at the very least, not change their behavior). But I'd actually expect this to be something that has to be addressed on a case-by-case basis (it depends on what the pragmas do as to how conflicts ought to be resolved). Feel free to prove me wrong, though. **************************************************************** From: Bob Duff Sent: Sunday, December 9, 2012 4:09 PM AI12-0003-1 -- A pragma Standard_Storage_Pool is introduced. I hope you all are happily and safely travelling to your destinations, especially those who, like Randy, may be facing ice&snow. I'd like to greet you on arrival with an explanation of my point of view about this "standard storage pool" business. I think I can prove that having a name for this variable is trivial to implement on all Ada implementations, including any that might exist in the future. (Proof beyond a reasonable doubt, I mean -- of course I'm not talking about a maths/logic proof.) If you think my proof is wrong, which is always a possibility I can't deny, please explain why. You have to point to some step in the proof that you think is bogus. In the past, I've been frustrated that people seemed not to understand my proof and/or responded with irrelevant arguments that didn't address the proof itself. If you agree with my proof, please say so, even if you don't think it's the way to go for some other reason. Please don't JUST state the other reason. I guess the third possibility is that you don't understand my proof. Say that, then, and I'll try to clarify. First, I think terms like "the standard storage pool" and "the global heap" have been misleading some people. In an implementation that concocts a new storage pool for each access type (which we wish to remain a valid implementation) there is no "THE pool" -- there are many. And what about an impl that doesn't really use storage pools at all by default -- maybe it calls 'malloc' directly? How can it provide access to THE pool used by default, when there is no such pool? My answer is that we are NOT trying to provide a name for "THE pool that is used by default for all access types that don't have a Storage_Pool clause". No. That is entirely unnecessary, and clearly impossible in some implementations. And anyway, it's the wrong level of abstraction for language rules. It is important that we do NOT want to force implementations to change their heap-allocation strategy in any way. All we want to do is to provide a way to "hook into" that strategy, explicitly. We are trying to provide access to SOME pool that is suitable for use in a Storage_Pool clause, and whose use invokes the implementation's default allocation behavior. And we want to make that efficient in most cases (namely, all the cases where the default is already efficient). I claim that the simplest way to do that is to declare a pool variable somewhere. And I claim that that's trivial to implement. Now here's the proof that it's trivial to implement: Today, I can say: type My_Access_Type is access all String; The_Standard_Storage_Pool: Root_Storage_Pool'Class renames My_Access_Type'Storage_Pool; I can make The_Standard_Storage_Pool visible throughout my program, and I can use it in Storage_Pool clauses for any access type I like. And make it the default pool, program-wide or more locally. If I can do that, then an Ada implementation can do it, too. And if the implementation does it, it can know what Tag is My_Access_Type'Storage_Pool'Tag, so it can declare The_Standard_Storage_Pool to be of a specific type, so no dispatching is involved in allocation, and the [De]Allocate procedures can be inlined. An implementation that doesn't "really" use pools by default can special case The_Standard_Storage_Pool. It can trivially recognize "for T'Storage_Pool use The_Standard_Storage_Pool;" and just use its default mechanisms. (This only makes sense if the default mechanisms are more efficient.) Note that it doesn't matter at all what those default mechanisms are. That's why I can prove my assertion even for implementations I have never seen! The default mechanisms could involve direct calls to 'malloc', or separate pools for each access type, or separate for each type, or... In other words, an implementation can easily pretend to be using pools even if it isn't under the hood. Furthermore, implementations already have to support the 'Storage_Pool query. If they can do that, they can trivially provide a name for whatever pool is returned by one particular such query. It is true that if we have The_Standard_Storage_Pool, users could pass it off to someplace that doesn't know it's the standard one -- all it knows is Root_Storage_Pool'Class. In that case, dispatching calls are needed, and the supposedly-more-efficient default mechanisms can't be used. But so what? That's already the case if the user does the exact same thing with My_Access_Type'Storage_Pool. Q.E.D. Actually, since it's not a maths/logic proof, I should instead say "I rest my case." ;-) The astute reader will have noticed that the same proof can be used to prove that we don't really *need* this feature. The user already has a way to get at some global pool that uses the default mechanisms, although possibly with some run-time overhead. The_Standard_Storage_Pool as declared by the user is class-wide. A clever compiler can know the Tag, and therefore avoid dispatching, and allow inlining. I can certainly live without this feature, but if we have it, I am convinced that the best way to provide it is to declare the standard storage pool as a variable somewhere in the predefined environment, of some impl-def pool type. That's much simpler than providing a whole new Standard_Storage_Pool pragma. I am opposed to adding a new pragma when it's not necessary (although I admit the new pragma isn't particularly complicated -- it's just different, and unnecessary). I note again: We neither need nor want any sort of requirement that this global pool variable actually be *used* by default -- if you look under the hood, you might well find something entirely different going on. Remember the "as if" meta-rule! During the meeting, someone asked where should this variable be declared. If that was meant as an honest question, then the answer is, "I don't know, and I don't care." It's just like any other new feature added to the predefined environment: we'll pick some existing package, or invent a new package, possibly a child of System.Storage_Pools. OTOH, if that question was meant as a challenge, along the lines of "If you don't know where to put it, then that's an argument against having it", then I reject that argument as bogus. I'm quite sure any one of us, including me, can figure out a reasonable package to put it in. We also need to decide on the name of the variable. I think Standard_Storage_Pool is just fine. The only people it was confusing were implementers, or people worrying about implementation issues. For users, it makes perfect sense. **************************************************************** From: Robert Dewar Sent: Sunday, December 9, 2012 5:08 PM > AI12-0003-1 -- A pragma Standard_Storage_Pool is introduced. The implementation difficulty in GNAT with any standard storage pool approach has always been the issue of consistency between separate compilations. SO whatever design is chosen needs to bear this in mind if it wants to get implemented. There are enough people on the ARG familiar with the GNAT implementation model to properly consider this important point, so no need to give more technical detail here :-) > I can make The_Standard_Storage_Pool visible throughout my program, > and I can use it in Storage_Pool clauses for any access type I like. > And make it the default pool, program-wide or more locally. > If I can do that, then an Ada implementation can do it, too. > And if the implementation does it, it can know what Tag is > My_Access_Type'Storage_Pool'Tag, so it can declare > The_Standard_Storage_Pool to be of a specific type, so no dispatching > is involved in allocation, and the [De]Allocate procedures can be inlined. I don't think this really properly takes the consistency problem into account! > The astute reader will have noticed that the same proof can be used to > prove that we don't really *need* this feature. The user already has a > way to get at some global pool that uses the default mechanisms, > although possibly with some run-time overhead. > The_Standard_Storage_Pool as declared by the user is class-wide. A > clever compiler can know the Tag, and therefore avoid dispatching, and allow inlining. Well I thought the real need was to take an existing program and change the default storage pool that was used WITHOUT having to decorate access types throughout the program **************************************************************** From: Bob Duff Sent: Sunday, December 9, 2012 5:43 PM > Well I thought the real need was to take an existing program and > change the default storage pool that was used WITHOUT having to > decorate access types throughout the program That capability already exists in Ada 2012 -- see pragma Default_Storage_Pool, which can be used as a config pragma, or more locally. AFAIK, GNAT correctly implements it. **************************************************************** From: Robert Dewar Sent: Sunday, December 9, 2012 5:59 PM I don't think so actually, since the consistency problem is not properly addressed, I think it would not be that hard to add, but I am pretty sure it is not done right now! **************************************************************** From: Tucker Taft Sent: Sunday, December 9, 2012 10:04 PM I agree that it is straightforward to create a "pseudo" storage pool which when specified as the storage pool for an access type, has the effect of it using the "normal" storage allocation and deallocation mechanisms. I might suggest making it a special attribute rather than a special object, e.g.: for Acc_Type'Storage_Pool use System.Storage_Pools'Standard; or for Acc_Type'Storage_Pool use Standard'Storage_Pool; This would make its "magicness" quite apparent. And the standard storage pool could be specified using the Default_Storage_Pool pragma, perhaps as follows: pragma Default_Storage_Pool(Standard'Storage_Pool); **************************************************************** From: Randy Brukardt Sent: Monday, December 10, 2012 12:53 AM > I hope you all are happily and safely travelling to your destinations, > especially those who, like Randy, may be facing ice&snow. Temps were just above freezing in Detroit and here in Madison, although my car had a couple inches of melting snow on it. No ice through, and the only problem was that they put my luggage on the earlier flight so it arrived in Madison 90 minutes before I did. (So it didn't come out with the other luggage - it turned out to be in the luggage office.) ... > If you think my proof is wrong, which is always a possibility I can't > deny, please explain why. You have to point to some step in the proof > that you think is bogus. It's not completely bogus, but... ;-) ... > Now here's the proof that it's trivial to implement: > > Today, I can say: > > type My_Access_Type is access all String; > > The_Standard_Storage_Pool: Root_Storage_Pool'Class > renames My_Access_Type'Storage_Pool; > > I can make The_Standard_Storage_Pool visible throughout my program, > and I can use it in Storage_Pool clauses for any access type I like. > And make it the default pool, program-wide or more locally. Here's the problem. You can do that, but there is no guarantee that it would work. (That is, the pool might raise an exception if you attempt to allocate some other type with it.) It seems *likely* that it would work, but I don't think we should be designing the language based on likelihoods. (Aside: If you are going to do this, I'd probably suggest writing the array in terms of storage elements rather than characters. They're not the same on some machines, and that could matter.) Specifically, we know that the language allows building different "standard" pools for different kinds of types. And for such an implementation, any specific pool is only guaranteed to work on the same sort of type. I presume (please correct me if I am wrong) that the reason you chose this particular type is that you can cause an allocation of essentially any size for this type. Thus one might conclude that the pool would have to work for any type. But that's not necessarily true. For Janus/Ada, at least, an unconstrained array type is allocated in two parts, a fixed size descriptor (the same for any value of the type) and an data area whose size depends upon the bounds. One could easily imagine a pool that puts those two different parts into different parts of memory because the different usage characteristics. Such a pool would raise an exception if the initial allocation wasn't for a descriptor. This isn't purely a thought experiment: I actually wrote such a pool for Windows 98, as the heap for a number of Windows versions had a relatively small maximum size; to be able to use all of the memory in the system, I had to manage the virtual memory for the data areas manually (this is not needed on modern Windows). The pool failed any calls to Allocate that were not clearly part of an array allocate. I never used it as the standard pool -- but surely the possibility exists (and needs to exist, IMHO, because it's hard to guess the requirements needed for kernels, nor the requirements of future users). > If I can do that, then an Ada implementation can do it, too. Probably 98% of the time this is true, but not 100%, as described above. > An implementation that doesn't "really" use pools by default can > special case The_Standard_Storage_Pool. It can trivially recognize > "for T'Storage_Pool use The_Standard_Storage_Pool;" > and just use its default mechanisms. (This only makes sense if the > default mechanisms are more efficient.) I don't think that most implementations would actually do this - it's a lot of extra work and it isn't absolutely necessary. Most of the Ada implementers (not counting AdaCore) don't have large staffs and we tend to do just enough to get by until/unless an actual customer cares a lot. This is not a case where implementing the better mechanism is going to be *required* to get this to work. (OTOH, I doubt much that the better mechanism would provide enough added performance to be noticeable in most cases. The main advantage of such pools is to reduce or eliminate fragmentation, which isn't going to be visible to most customers.) Anyway, this is probably irrelevant to your argument, which is in any case built on a foundation of sand (see above). ... > In other words, an implementation can easily pretend to be using pools > even if it isn't under the hood. I don't agree that it is "easy"; it's easier than dynamic accessibility checking :-) but hardly trivial. ... > The astute reader will have noticed that the same proof can be used to > prove that we don't really *need* this feature. > The user already has a way to get at some global pool that uses the > default mechanisms, although possibly with some run-time overhead. > The_Standard_Storage_Pool as declared by the user is class-wide. A > clever compiler can know the Tag, and therefore avoid dispatching, and > allow inlining. And that's also not true, in the sense that it's impossible for the user to know what type that they can declare which will guarantee them a globally useful pool. Certainly, I've shown that an unconstrained array isn't *always* going to be such a type. (For Janus/Ada, it doesn't matter ("new" is just a single pool), but I would not want to constrain implementations as much as you are willing to.) > I can certainly live without this feature, but if we have it, I am > convinced that the best way to provide it is to declare the standard > storage pool as a variable somewhere in the predefined environment, of > some impl-def pool type. That's much simpler than providing a whole > new Standard_Storage_Pool pragma. I am opposed to adding a new pragma > when it's not necessary (although I admit the new pragma isn't > particularly complicated -- it's just different, and unnecessary). I would rather have added a special parameter to the existing Default_Storage_Pool pragma, as the entire point is to turn off the effect of that pragma and return to the default. For that purpose, using a specially named pool seems misleading (because using that pool is *not* what you want to do). But we couldn't find a decent name for such a parameter, so we decided to define another pragma instead. ... > During the meeting, someone asked where should this variable be > declared. If that was meant as an honest question, then the answer > is, "I don't know, and I don't care." Which is not a helpful answer. We do need to know, because we are going to be comparing the "weight" of the various proposed solutions. Adding a new subclause (to define a new package), is certainly going to be "heavier" than just adding a new pragma (or argument) to an existing clause. If, of course, you can find a reasonable *existing* place to put it, the "weight" is less. ... > We also need to decide on the name of the variable. I think > Standard_Storage_Pool is just fine. The only people it was confusing > were implementers, or people worrying about implementation issues. For > users, it makes perfect sense. Other than it doesn't exist. :-) We'd need to rewrite the 13.11 section to use the term "standard storage pool" in order to call it that where you define it. (This is not a big rewrite, probably just a few sentences, but for someone complaining about unnecessary wording changes, I'm surprised that you are insisting on one...) **************************************************************** From: Jean-Pierre Rosen Sent: Monday, December 10, 2012 3:13 AM > I agree that it is straightforward to create a "pseudo" storage pool > which when specified as the storage pool for an access type, has the > effect of it using the "normal" storage allocation and deallocation > mechanisms. > [...] > pragma Default_Storage_Pool(Standard'Storage_Pool); > OK, Bob "demonstrated" that it is possible to have a pseudo-storage pool, whose meaning can be interpreted as "this is not a real storage pool, it implies just use the standard allocation mechanism". No kidding! If we want the standard allocation mechanism, which might not use a storage pool with the conventional meaning, by all means, let's tell it! I fail to see what the problem is with a new pragma. One more paragraph? Certainly not more effort than the definition of the attribute that Tuck proposes (including all the hand-waiving that this storage pool needs not be a "real" storage pool). And the pragma simply tells the truth! **************************************************************** From: Erhard Ploedereder Sent: Sunday, December 9, 2012 8:51 AM I agree with the proof. In the matter, I do not feel strongly one way or the other. In favor of the name approach is that the name can also be used in an aspect specification. I was very serious in asking where such a declaration would reside. Note the user convenience aspect between: pragma Standard_Storage_Pool; and pragma Default_Storage_Pool(System.Storage_Pools.Standard.Standard_Storage_Pool); (sorry, my mailer automatically wraps long lines. Really. :-) ) This is just plain ugly keyboard training for programmers. Or, maybe, an Ada API spelling bee. ("Is is Standard.Storage_Pool, or Pools, or ...?") The alternative of making a syntactic rule that would magically allow pragma Default_Storage_Pool(Standard_Storage_Pool); I would find disgusting, even if already present on some pragmas. It would complicate the RM writeup. And, it would not help with aspect specifications. **************************************************************** From: Bob Duff Sent: Sunday, December 9, 2012 4:40 PM Here's the other issue I'd like clarify: While working on AI12-0003-1, Erhard discovered a bug. In particular, the wording for Default_Storage_Pool refers to "immediate scope of a pragma", which is a concept that is not explicitly defined in the RM. I voted against giving Erhard and Steve action items to fix this bug (Steve is supposed to figure out how to define the term, and Erhard is supposed to figure out how to use some other term involving "regions" or something). In my opinion: - We do NOT need to fix every known bug in the RM. - We SHOULD fix some bugs, but we should NOT fix some others. We can decide on a case-by-case basis. - This particular bug is not worth fixing. I realize (given the vote) that all the rest of ARG disagrees with me at least on the last point. I accept that, and I'm not trying to convince anyone -- just explaining my position. Randy seemed to interpret my words as "we should never fix RM bugs", and was therefore shocked and appalled. Well, I didn't say that, and I didn't mean to imply it. Note that the bug in question is not directly related to AI12-0003. If we fix it, it should be under a different AI. I don't remember for sure, but I think I put this bug in deliberately. That is, I figured "immediate scope" is well defined for declarations, and it's pretty obvious what it should mean for pragmas that are declarative_items, and it's just being pedantic to fiddle with the wording in chap 8 just for this little pragma. I expect we will continue to find bugs in the RM, and we will continue to fix them, and I will continue to vote against fixing them when I think it's a waste of time and/or not worth the risk. I don't think that should anger anyone -- it's just a difference of opinion. **************************************************************** From: Erhard Ploedereder Sent: Tuesday, December 11, 2012 6:44 PM > Note that the bug in question is not directly related to AI12-0003. If > we fix it, it should be under a different AI. Indeed. > I don't remember for sure, but I think I put this bug in deliberately. Shame on you ;-) > That is, I figured "immediate scope" is well defined for declarations, > and it's pretty obvious what it should mean for pragmas that are > declarative_items, and it's just being pedantic to fiddle with the > wording in chap 8 just for this little pragma. I actually find this notion more understandable (and more commonly used) than the "applies to a region" concept followed in the Suppress and Assertion_Policy pragmas. I can't help but wonder whether there are subtle differences. So I don't mind digging into this for my enlightenment. **************************************************************** From: Erhard Ploedereder Sent: Sunday, June 9, 2013 5:48 PM Attached is the revised version incorporating the decisions of the last meeting and Steve's words about immediate scopes of pragmas, which Randy had already put into the AI. [This is version /04 of the AI - Editor.] As charged, I investigated the use of the region concept, but gladly left it behind after Steve's simple addition, since the immediate scope notion is vastly preferable, anyway. **************************************************************** From: Brad Moore Sent: Saturday, January 17, 2015 1:29 PM I'm looking at my homework relating to specifying the default storage pool, and have a question. At the last ARG meeting, Tucker provided some guidance and suggested that it be illegal if (without any context) (Standard) denotes anything other than package Standard." This is to deal with the situation where someone specifies the default storage pool as "Standard" which is an identifier specific to the pragma, when there is another declaration that is directly visible having the same name. My original approach would be to disallow any such name conflict, but I think that may be too draconian. eg. type Foo is interface; function Standard (Item : Foo) return Integer; pragma Default_Storage_Pool (Standard); -- Legal? type Foo_Access is access Foo; I think it's clear here that the Standard in the pragma is not referring to the Standard function. I'm thinking that it would be better to define legality such that only conflicts with other directly visible storage pool declaration names are disallowed. Specifically, it would be illegal to specify the Default_Storage_Pool pragma as Standard, if there is a directly visible storage pool declaration with the name "Standard". Alternatively, we could simply disallow declaring storage pools that have the name "Standard", but that would introduce a minor backwards incompatibility. It seems pretty minor and quite unlikely to occur in practice, but perhaps such an incompatibility should be eliminated if there is another solution such as what I initially proposed, that doesnt have this incompatibility. Thoughts? **************************************************************** From: Randy Brukardt Sent: Saturday, January 17, 2015 6:28 PM I think this is a non-problem. I'd be happy with no check at all, but if we have to have one, I think it should be as simple as possible. That's mainly because "Standard" is one of those identifiers in Ada that aren't reserved, but should be treated as if they are. You don't want to be declaring things named "Standard" anymore than you want to declare things named "Integer" or "Character". You *can* do that, but it's an invitation to confusion. So I don't really care if the check picks up things that aren't really going to be confused. Because they're not likely to exist anyway. Indeed, I'd probably implement this check as "if there is more than one definition of Standard in the current symboltable, reject the pragma". That is, I wouldn't pay any attention to visibility or what's being declared. Most likely, that would pick up a few cases that aren't a problem, but (A) there probably isn't going to be an ACATS test that could tell the difference; and (B) this will never happen in practice. In the amazingly unlikely event that that simple check causes a problem for someone, I'd upgrade it to using identifier lookup (which does use visibility); then "if there is more than one visible Standard, reject the pragma". This is still rather simple, as no resolution is needed. Your check would require bringing the entire machinery of resolution into the picture (after all, "Standard" could be an object, but it also could be a parameterless function call). That seems like swatting a fly with a bazooka. To summarize, I'd prefer to stick with the original idea -- the simpler the check, the better. **************************************************************** From: Brad Moore Sent: Sunday, January 18, 2015 11:10 AM OK, will do. ****************************************************************