!standard 4.9(14) 09-02-12 AC95-00170/01 !class Amendment 09-02-12 !status received no action 09-02-12 !status received 08-11-14 !subject Storage pools for anonymous allocators !summary !appendix From: Franco Gasperoni Date: Friday, November 14, 2008 10:47 AM We could at the syntactic level decide to associate a storage pool with all anonymous allocators. For instance we could write (pick your favorite attribute name): for T'Access_Storage_Pool use ...; or for T'Access'Storage_Pool use ...; We could even forbid the use of anonymous allocators with a Storage_Size clause of 0. For instance we could write (pick your favorite attribute name): for T'Access_Storage_Size use 0; or for T'Access'Storage_Size use 0; The above forbids the use of anonymous allocators "new T". These Storage_Pool and Storage_Size clauses should occur (if any) in the same package or wherever T is declared. Furthermore we could defined the following predefined package: package System.Storage_Pools.Default_Pools is type Default_Pool_Type is ; Default_Pool : Default_Pool_Type; private ... implementation defined end System.Storage_Pools.Default_Pools; If no Storage_Pool or Storage_Size clause is specified for anonymous allocators then the Default_Pool is used for them. As always, the "as if" rule applies: There is of course no requirement that the generated machine code actually call Allocate(Default_Pool, ...). The compiler can have hardwired knowledge of what this pool does, and generate the appropriate code inline. The next question is of course how do we deallocate the objects allocated with these anonymous "new T". One "simple" answer is garbage collection of course :) The other is for every type T, the attribute T'Free denotes either a procedure: procedure T'Unchecked_Free (X : in out access T); (radical approach requires that we allow "in out" for access parameters), or function T'Unchecked_Free (X : access T) return access T; (and if T is tagged the equivalents for "access T'Class") The above behaves as Unchecked_Deallocation: finalizes X.all, frees the storage by calling Deallocate on T'Access'Storage_Pool, and sets X to null (procedure case) or returns null. In the function approach we would use it as follows: Ptr : access T := new T; ... Ptr := T'Unchecked_Free (Ptr); **************************************************************** From: Randy Brukardt Date: Friday, November 14, 2008 2:07 PM ... > Furthermore we could defined the following predefined package: > > package System.Storage_Pools.Default_Pools is > type Default_Pool_Type is ; > Default_Pool : Default_Pool_Type; > private > ... implementation defined > end System.Storage_Pools.Default_Pools; > > If no Storage_Pool or Storage_Size clause is specified for anonymous > allocators then the Default_Pool is used for them. We tried something like this the last time (to give a name to the default pool) - see AI95-0300. It was rejected because there is no such thing as *the* default pool; for many implementations, at least, there are many default pools depending on the location of the declaration of the access type. That's certainly true in the case of an access parameter (assuming you follow the Implementation Advice), since the idea is to allocate it locally, and that surely is not the normal global default pool (usually a heap). So I don't understand this part of your idea at all. **************************************************************** From: Randy Brukardt Date: Friday, November 14, 2008 3:07 PM > We could at the syntactic level decide to associate a storage pool > with all anonymous allocators. This to me seems to be a horribly bad idea. By doing so globally, you make it impossible for subsystems written by different teams to get along -- they both may want their own custom storage pool (or expect the default one). If we are going to do something like this (and I am *not* commenting on the merits of the idea itself), it has to specifiable locally, so a single package/subprogram/whatever can specify the pool for its anonymous access types without affecting anything else. That will complicate the idea a lot, I fear. **************************************************************** From: Tucker Taft Date: Saturday, November 15, 2008 8:34 AM I'm not convinced this is a problem worth solving. In my experience, the code involved in creating objects is often relatively distinct from the usually much larger amount of code involved in manipulating them. The "idiom" that I have seen used pretty frequently is that the access type used for manipulation is *not* the same as the one used for allocation and deallocation. With anonymous access types, this becomes even more necessary, but no more onerous (actually, less onerous, since you don't need to do an explicit conversion on top of the explicit type qualification). For example, I find this kind of thing to be pretty common and often useful: X : Acc_T := Acc_T (Allocation_Acc_T'(new T)); That is, the allocation type "Allocation_Acc_T" determines the storage pool to be used, and Acc_T is the type used for most manipulation of the data. This allows a separation of concerns between allocation/ deallocation and manipulation, and allows the same data structure to be manipulated independently of the storage pool used for allocation/deallocation. With anonymous access types, this paradigm becomes even more straightforward: X : access T := Allocation_Acc_T'(new T); Often all allocation is hidden in some kind of "factory" routine, and it is there that this kind of code can be buried, and it is only there where you actually care what storage pools are to be used for allocation. If you are going to go to the trouble of defining your own storage pool and specifying it with a representation clause, it seems a small step to define a named access type to associate with it. As I mentioned in another note, AI05-111 is also trying to address this issue, but it has a somewhat different goal. It is trying to associate shorter-lived storage (sub) pools with sets of objects, rather than with a whole access type. Your proposal is going somewhat in the opposite direction, by dumping almost everything into a single, presumably very-long-lived storage pool. I think there is a separate, somewhat different concern, having to do with how to specify a user-defined storage pool for the "default" storage pool. I believe a number of compilers provide something like that, and it would probably be worth standardizing, but an effort along those lines should start with a survey of what compilers currently do in that area. **************************************************************** From: Franco Gasperoni Date: Sunday, November 16, 2008 1:58 AM > With anonymous access types, this paradigm becomes even more > straightforward: > > X : access T := Allocation_Acc_T'(new T); > > Often all allocation is hidden in some kind of "factory" > routine, and it is there that this kind of code can be buried, and it > is only there where you actually care what storage pools are to be > used for allocation. I understand and like your approach. If there was a way at partition unit level to ensure that accidental X : access T := new T; are forbidden then all would be well. ****************************************************************