Version 1.1 of acs/ac-00170.txt

Unformatted version of acs/ac-00170.txt version 1.1
Other versions for file acs/ac-00170.txt

!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 <implementation defined>;
       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 <implementation defined>;
>        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.

****************************************************************


Questions? Ask the ACAA Technical Agent