Print

Print


From:  Stanley Allen <[log in to unmask]>

> 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;
> private
>     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
> begin
>     Put_Line ("Count is:" & Integer'Image (Final.Get_Count));
>     declare
>         X : Final.Finis := Final.Create;
>     begin
>         Put_Line ("Count is:" & Integer'Image (Final.Get_Count));
>     end;
>     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.

I'm not sure what exactly the program is supposed to do... if it's
just to increment a global counter whenever an object of type Finis is
created and decrement it whenever an object goes away -- e.g., print "0,
1, 0 -- then you need to override Initialize to do the increment (don't
do it in Create), right?


> 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.

The user can do that because you made the full declaration of the type
public.  Declare the public view of the type as follows:

        type Finis is private;

...and move the full declaration and the declarations of Initialize
and Finalize to the private part.