TEAM-ADA Archives

Team Ada: Ada Programming Language Advocacy


Options: Use Forum View

Use Monospaced Font
Show Text Part by Default
Condense Mail Headers

Message: [<< First] [< Prev] [Next >] [Last >>]
Topic: [<< First] [< Prev] [Next >] [Last >>]
Author: [<< First] [< Prev] [Next >] [Last >>]

Print Reply
"Team Ada: Ada Advocacy Issues (83 & 95)" <[log in to unmask]>
Tucker Taft <[log in to unmask]>
Sat, 9 May 1998 03:01:36 -0500
Stanley Allen <[log in to unmask]>
text/plain; charset=us-ascii
Stanley Allen <[log in to unmask]>
text/plain (158 lines)
Tucker Taft wrote:
> If you want to prevent the possibility of forgetting initial
> value assignment, you could specify unknown discriminants
> in the private type declaration.  E.g.:
>     type Object_Type(<>) is private;
> The full type need not have any discriminants at all, but by
> doing the private declaration this way, a user of the type outside
> the package is required to initialize all object declarations,
> because simply "X : Object_Type;" is illegal (Object_Type is an
> "indefinite" (view of a) type).

This is a good suggestion, but it only gets you about
half way there.  I want to be able to do the opposite
as well: guarantee that *every* object creation
causes one of my procedures to be called.

Consider this example:

with Ada.Finalization; use Ada.Finalization;
package Final is
    type Finis(<>) is private;
    function Get_Count return Integer;
    function Create return Finis;
    type Finis is new Controlled with null record;
    procedure Finalize (Obj : in out Finis);
    Null_Finis : constant Finis := (Controlled with null record);
end Final;

package body Final is
    Ref_Count : Integer := 0;

    procedure Finalize (Obj : in out Finis) is begin
        Ref_Count := Ref_Count - 1;
    end Finalize;

    function Get_Count return Integer is begin
        return Ref_Count;
    end Get_Count;

    function Create return Finis is begin
        Ref_Count := Ref_Count + 1;
        return Null_Finis;
    end Create;

end Final;

with Final;
with Text_Io; use Text_Io;
with Ada.Finalization; use Ada.Finalization;
procedure Finish is
    Put_Line ("Count is:" & Integer'Image (Final.Get_Count));
        X : Final.Finis := Final.Create;
        Put_Line ("Count is:" & Integer'Image (Final.Get_Count));
    Put_Line ("Count is:" & Integer'Image (Final.Get_Count));
end Finish;

The output of Finish is:

Count is: 0
Count is: 0
Count is:-1

My understading is that we get this result because the
object resulting from the Create call is finalized without
having been initialized.  So, in Ada 95, I can't figure out
a way to do reference counting for every object created
of my type.  (In C++, this would be done with a private
"static" data member in the class.)

The following is not enough:

with Ada.Finalization; use Ada.Finalization;
package Final is

    type Finis is new Controlled with null record;  -- or with private

    -- Construct is a procedure, not a function, so that
    -- it cannot be called for object initialization
    procedure Construct
         (Obj : in out Finis;
          A : type1; B : type2 ... );   -- construction parameters
    procedure Initialize (Obj : in out Finis);
    procedure Finalize (Obj : in out Finis);

end Final;

(where the body of Initialize increments the ref_count,
the body of Finalize decrements ref_count), because it
is not possible to keep the user from explicitly
initializing objects of type Finis like this:

    F : Final.Finis := (Controlled with null record);

This bypasses the call to Initialize.  (I know I
can guarantee that Initialize will be called if Finis
is derived from Limited_Controlled, but this misses
the point because then I would not be able to use
functions as contructors, and would be stuck with
discriminant values if I wanted parameters to be
supplied at object declaration.)

What would solve this problem (and a number of others),
I think, is added support in Ada.Finalization for
user-defined activity at the time of object creation.

This could take the form:

    procedure Create (Object : in out Controlled);    ....
    procedure Create (Object : in out Limited_Controlled);

in the spec of Ada.Finalization.

The semantics are: Create is called at object creation
time, just before initialization.

Symmetrically, we could add:

    procedure Destroy (Object : in out Controlled);   ....
    procedure Destroy (Object : in out Limited_Controlled);

Which have the semantics: Destroy is called when an
object is destroyed, just after the last Finalize
has been called for it before it goes out of

Adding a separate Destroy procedure would help
clean up the current semantics of Finalize because
a Finalize procedure actually does double duty in an
Ada 95 program -- it handles both value-destruction
and object-destruction.

Ada 95 Initialize/Adjust/Finalize are not as flexible
as C++ constructor/destructors because the have only
to do with the *contents* of an object during its life
*between* creation and deletion.  It would be nice to
extend the programmer's control to permit activity at
the endpoints of the object lifetime as well.

Is there anything about this (admittedly rough) proposal
which violates "Ada theory" (as I like to call it)?

Stanley Allen
mailto:[log in to unmask]