comp.lang.ada
 help / color / mirror / Atom feed
* Q. on Automatic Package Finalization
@ 1996-09-22  0:00 david scott gibson
  1996-09-23  0:00 ` Robert Dewar
  0 siblings, 1 reply; 12+ messages in thread
From: david scott gibson @ 1996-09-22  0:00 UTC (permalink / raw)



Hi.  Does anyone know of a good way to achieve automatic package
finalization in Ada95?  I'd like to create a generic package which
automatically cleans up its package instance state (possibly including
allocated memory, temporary files, etc.) when the package scope ends.
The code below (which compiles under GNAT 3.05) is one attempt to
achieve this using controlled types.  It requires that the
representation of state for package P instances be incorporated into
an instance (pkg_var) of a controlled type (PC.T) declared
in a library-level package (PC).  This is not a very satisfactory
solution even if it would work.  Does anyone have some better
ideas for handling automatic package finalization?

Dave
--
dgibson@cis.ohio-state.edu

----------------------------------------
-- pc.ads

with Ada.Finalization;

package PC is               -- library level since controlled

    type T is new Ada.Finalization.Controlled with 
        record
            rep: Integer;   -- representation for pkg P's variables
        end record;         -- non-privtate for P direct access
                       
    procedure Finalize(     
            x: in out T
        );

end PC;

----------------------------------------
-- pc.adb

with Ada.Text_IO;

package body PC is

    procedure Finalize_Package (x: in out T) is
    begin
        Ada.Text_IO.Put_Line("Finalizing package P");
        x.rep := 0;
    end Finalize_Package;

    procedure Finalize(
                x: in out T
            ) is
    begin
        Finalize_Package(x);
    end Finalize;

end PC;

----------------------------------------
-- p.ads

with PC;

generic

package P is

    type T is private;

    procedure Initialize_Package (x: in out PC.T);

private

    type T is 
        record
            rep: PC.T;
        end record;

end P;

----------------------------------------
-- p.adb

with Ada.Text_IO;

package body P is

    pkg_var: PC.T; 

    procedure Initialize_Package (x: in out PC.T) is
    begin
        Ada.Text_IO.Put_Line("Initializing package P");
        x.rep := 1;
    end;

begin
   Initialize_Package(pkg_var);
end P;

----------------------------------------
-- ptest.adb

with P;

procedure PTest is                -- output:

    package PI1 is new P;         -- Initializing package P

begin

    declare
        package PI2 is new P;     -- Initializing package P
    begin
        null;
    end;                          -- Finalizing package P

end PTest;                        -- Finalizing package P




^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Q. on Automatic Package Finalization
  1996-09-22  0:00 david scott gibson
@ 1996-09-23  0:00 ` Robert Dewar
  1996-09-24  0:00   ` Norman H. Cohen
                     ` (2 more replies)
  0 siblings, 3 replies; 12+ messages in thread
From: Robert Dewar @ 1996-09-23  0:00 UTC (permalink / raw)



iDave said

"Hi.  Does anyone know of a good way to achieve automatic package
finalization in Ada95?  I'd like to create a generic package which
automatically cleans up its package instance state (possibly including
allocated memory, temporary files, etc.) when the package scope ends.
The code below (which compiles under GNAT 3.05) is one attempt to
achieve this using controlled types.  It requires that the
representation of state for package P instances be incorporated into
an instance (pkg_var) of a controlled type (PC.T) declared
in a library-level package (PC).  This is not a very satisfactory
solution even if it would work.  Does anyone have some better
ideas for handling automatic package finalization?"

This seems a perfectly reasonable approach, and indeed it was knowing
that this approach existed that made it seem unwise to clutter the language
with yet another feature for handling this case specifically.





^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Q. on Automatic Package Finalization
  1996-09-23  0:00 ` Robert Dewar
@ 1996-09-24  0:00   ` Norman H. Cohen
  1996-09-24  0:00     ` Tucker Taft
  1996-09-25  0:00   ` Jens Jakob Jensen
  1996-09-25  0:00   ` Norman H. Cohen
  2 siblings, 1 reply; 12+ messages in thread
From: Norman H. Cohen @ 1996-09-24  0:00 UTC (permalink / raw)



Robert Dewar wrote:
> 
> iDave said
> 
> "Hi.  Does anyone know of a good way to achieve automatic package
> finalization in Ada95?  I'd like to create a generic package which
> automatically cleans up its package instance state (possibly including
> allocated memory, temporary files, etc.) when the package scope ends.
> The code below (which compiles under GNAT 3.05) is one attempt to
> achieve this using controlled types.  It requires that the
> representation of state for package P instances be incorporated into
> an instance (pkg_var) of a controlled type (PC.T) declared
> in a library-level package (PC).  This is not a very satisfactory
> solution even if it would work.  Does anyone have some better
> ideas for handling automatic package finalization?"
> 
> This seems a perfectly reasonable approach, and indeed it was knowing
> that this approach existed that made it seem unwise to clutter the language
> with yet another feature for handling this case specifically.

To be honest, I don't think we realized it would be so complicated
during the Ada 9X design reviews.  The complication arises from the fact
that we would like the finalization of a "frame" (i.e., a block
statement or a body) to be able to refer to variables declared locally
inside that frame, but the rules about accessibility levels prevent us
from doing so.  David Gibson's solution--to declare a global template
for what should be local data--is clever, but David rightfully regards
it as ugly.

In other words, not yet being as accustomed as we are today to being
bitten by the accessibility rules ;-), we envisioned being able to do
something like

   with Ada.Finalization;

   procedure P is

      Local_Variable_1 : T1;
      Local_Variable_2 : T2;
      Local_Variable_3 : T3;
      ...

      package Frame_Finalization is 
         type Frame_Finalization_Type is
            new Ada.Finalization.Limited_Controlled  -- ILLEGAL!
               with null record;
         procedure Finalize (X: in out Frame_Finalization_Type);
         Frame_Finalization_Object: Frame_Finaliztion_Type;
      end Frame_Finalization;

      package body Frame_Finalization is
         procedure Finalize (X: in out Frame_Finalization_Type) is
         begin
            ...  -- references to the local variables of P
         end Finalize;
      end Frame_Finalization;

   begin  

       ...  -- statements of P, manipulating Local_Variable_1,
            --    Local_Variable_2, Local_Variable_3, ...

   end P;

(Upon departure from P, as Finalization_Object is about to cease to
exist, the Finalize procedure is invoked.)  We cannot really do this
because it is illegal to extend a library-level type such as
Ada.Finalization.Limited_Controlled except at library level (see RM
3.9.1(3)).  

David Gibson's problem was frame finalization not for a procedure, but
for a generic package.  He ran into a similar restriction, against
extending a library-level type in a generic body (RM 3.9.1(4)).  His
solution is to declare his controlled type at library level.  Instead of
declaring a dummy controlled type with no components, he gives the type
one record component for each of the local variables that the
finalization routine is to manipulate.  The finalization routine is
rewritten to manipulate the corresponding components of the object being
passed to it.  The local variables to be finalized are replaced by a
single object of the new controlled type.  The analog for the procedure
P above would be:

   package P_Wrapper is
      procedure P;
   end P_Wrapper;


   with Ada.Finalization;

   package body P_Wrapper is

      package Frame_Finalization is
     
         type P_State_Type is 
            new Ada.Finalization.Controlled with
               record
                  Local_Variable_1 : T1;
                  Local_Variable_2 : T2;
                  Local_Variable_3 : T3;
                  ...
               end record;

         procedure Finalize (X: in out P_State_Type);

      end Frame_Finalization;

      package body Frame_Finalization is
   
         procedure Finalize (X: in out P_State_Type) is
         begin
            ... -- references to components of X
         end Finalize;

      end Frame_Finalization;

      procedure P is
         P_State : P_State_Type; 
      begin
         ... -- statements of P, manipulating 
             --    P_State.Local_Variable_1,
             --    P_State.Local_Variable_2,
             --    P_State.Local_Variable_3, ...
      end P;

   end P_Wrapper;

The feature we considered during the 9X design, by the way, was simple,
succinct, and intuitive:  Everywhere Ada allows

   begin
      ...
   exception
      ...
   end

we would have allowed

   begin
      ...
   exception
      ...
   at end
      < sequence of frame finalization statements >
   end

The semantics would have been the same as the 

   try { ... } catch { ... } finally { ... }

construct in Java or

   TRY
      TRY
         ...
      EXCEPT
         ...
      END
   FINALLY
      ...
   END

in Modula-3:  The frame-finalization statements get executed both after
normal exit from a frame and after execution of an exception handler for
the frame.

-- 
Norman H. Cohen
mailto:ncohen@watson.ibm.com
http://www.research.ibm.com/people/n/ncohen




^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Q. on Automatic Package Finalization
  1996-09-24  0:00   ` Norman H. Cohen
@ 1996-09-24  0:00     ` Tucker Taft
  0 siblings, 0 replies; 12+ messages in thread
From: Tucker Taft @ 1996-09-24  0:00 UTC (permalink / raw)



Norman H. Cohen (ncohen@watson.ibm.com) wrote:

: ...
: David Gibson's problem was frame finalization not for a procedure, but
: for a generic package.  He ran into a similar restriction, against
: extending a library-level type in a generic body (RM 3.9.1(4)).  His
: solution is to declare his controlled type at library level.  Instead of
: declaring a dummy controlled type with no components, he gives the type
: one record component for each of the local variables that the
: finalization routine is to manipulate.  The finalization routine is
: rewritten to manipulate the corresponding components of the object being
: passed to it.  The local variables to be finalized are replaced by a
: single object of the new controlled type.   ...

Another approach would be to use access discriminants rather
than components.  The local variables of interest would need to
be aliased, so they could be referenced by the access discriminants
of the controlled object.

: ...
: Norman H. Cohen
: mailto:ncohen@watson.ibm.com
: http://www.research.ibm.com/people/n/ncohen

-Tucker Taft   stt@inmet.com   http://www.inmet.com/~stt/
Intermetrics, Inc.  Cambridge, MA  USA




^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Q. on Automatic Package Finalization
  1996-09-23  0:00 ` Robert Dewar
  1996-09-24  0:00   ` Norman H. Cohen
@ 1996-09-25  0:00   ` Jens Jakob Jensen
  1996-09-25  0:00   ` Norman H. Cohen
  2 siblings, 0 replies; 12+ messages in thread
From: Jens Jakob Jensen @ 1996-09-25  0:00 UTC (permalink / raw)



In article <324837B8.2361@watson.ibm.com>,
"Norman H. Cohen" <ncohen@watson.ibm.com> wrote:
[snippety-snip]
>The feature we considered during the 9X design, by the way, was simple,
>succinct, and intuitive:  Everywhere Ada allows
>
>   begin
>      ...
>   exception
>      ...
>   end
>
>we would have allowed
>
>   begin
>      ...
>   exception
>      ...
>   at end
>      < sequence of frame finalization statements >
>   end
>
>The semantics would have been the same as the 
>
>   try { ... } catch { ... } finally { ... }
>
>construct in Java or
>
>   TRY
>      TRY
>         ...
>      EXCEPT
>         ...
>      END
>   FINALLY
>      ...
>   END
>
>in Modula-3:  The frame-finalization statements get executed both after
>normal exit from a frame and after execution of an exception handler for
>the frame.

Does this include leaving the frame by return and abort ? I haven't looked
enough into these languages, I'm afraid.

If not, one could do something like:

procedure P is
   ...
   procedure Finalize is
      ...
   end Finalize;
   ...
begin
   ...
   Finalize;
exception
   when ... =>
      ...
      Finalize;
   when others =>
      Finalize;
      raise;
end P;

You have to be really sloppy to miss calling "Finalize" when adding an
exception handler later on. But it _will_ happen, of course...

>Norman H. Cohen
>mailto:ncohen@watson.ibm.com
>http://www.research.ibm.com/people/n/ncohen

-----------------------------------------------------------------------------
--          jjjensen@cybernet.dk   (current)                               --
-- Jens_Jakob_Jensen@mailhost.net  (permanent, thanks to www.pobox.org.sg) --
-----------------------------------------------------------------------------




^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Q. on Automatic Package Finalization
  1996-09-23  0:00 ` Robert Dewar
  1996-09-24  0:00   ` Norman H. Cohen
  1996-09-25  0:00   ` Jens Jakob Jensen
@ 1996-09-25  0:00   ` Norman H. Cohen
  2 siblings, 0 replies; 12+ messages in thread
From: Norman H. Cohen @ 1996-09-25  0:00 UTC (permalink / raw)



Jens Jakob Jensen wrote:
 
> In article <324837B8.2361@watson.ibm.com>,
> "Norman H. Cohen" <ncohen@watson.ibm.com> wrote:
...
> >              The frame-finalization statements get executed both after
> >normal exit from a frame and after execution of an exception handler for
> >the frame.
>
> Does this include leaving the frame by return and abort ? I haven't looked
> enough into these languages, I'm afraid.

Yes, and also by goto or loop exit out of a block statement, or by a
requeue statement.

-- 
Norman H. Cohen
mailto:ncohen@watson.ibm.com
http://www.research.ibm.com/people/n/ncohen




^ permalink raw reply	[flat|nested] 12+ messages in thread

* Q. on Automatic Package Finalization
@ 1996-09-28  0:00 Robert Dewar
  1996-10-04  0:00 ` Norman H. Cohen
  0 siblings, 1 reply; 12+ messages in thread
From: Robert Dewar @ 1996-09-28  0:00 UTC (permalink / raw)




rman said that we (Ada 9X) considered

">   begin
>      ...
>   exception
>      ...
>   at end
>      < sequence of frame finalization statements >
>   end"


Interestingly, internally GNAT implements at end, but does not allow it
to be mixed with an exception handler, and at end, unlike an exception
handler, covers the associated declarations.

It would be trivial (but a bit naughty) to make this available as a language
extension :-)





^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Q. on Automatic Package Finalization
@ 1996-09-28  0:00 Robert Dewar
  1996-10-04  0:00 ` Norman H. Cohen
  0 siblings, 1 reply; 12+ messages in thread
From: Robert Dewar @ 1996-09-28  0:00 UTC (permalink / raw)



iRegarding Norm's notes on finalization of packages.

Really the annoying thing is the restriction on controlled typs to the
outer level. This really is not something that the compilre requires. We
may provide some facility in GNAT to get around this restriction ...






^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Q. on Automatic Package Finalization
  1996-09-28  0:00 Q. on Automatic Package Finalization Robert Dewar
@ 1996-10-04  0:00 ` Norman H. Cohen
  1996-10-04  0:00   ` Robert Dewar
  0 siblings, 1 reply; 12+ messages in thread
From: Norman H. Cohen @ 1996-10-04  0:00 UTC (permalink / raw)



Robert Dewar wrote:
 
> ">   begin
> >      ...
> >   exception
> >      ...
> >   at end
> >      < sequence of frame finalization statements >
> >   end"
> 
> Interestingly, internally GNAT implements at end, but does not allow it
> to be mixed with an exception handler, and at end, unlike an exception
> handler, covers the associated declarations.

Both those differences detract from the value of "at end".  

First, the principal purpose of "at end" is to ensure that frame
finalization ALWAYS takes place, whether the frame is exited by reaching
the end of the frame, by handling an exception, by propagating an
unhandled exception, or by some nonlocal transfer of control (goto,
exit, return, requeue).

Second, if the "at end" statements are entered because of an exception
part way through the elaboration of declarations, some of the variables
visible in the "at end" section may not have been elaborated, so using
them in the frame finalization will be unsafe.  That is why the Ada
rules have an exception in a declarative part propagate an exception
rather than tranferring control to a handler of the same construct as
the declarative part; the same consideration applies to frame
finalization.

> It would be trivial (but a bit naughty) to make this available as a language
> extension :-)

More than a bit!

-- 
Norman H. Cohen
mailto:ncohen@watson.ibm.com
http://www.research.ibm.com/people/n/ncohen




^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Q. on Automatic Package Finalization
  1996-10-04  0:00 ` Norman H. Cohen
@ 1996-10-04  0:00   ` Robert Dewar
  0 siblings, 0 replies; 12+ messages in thread
From: Robert Dewar @ 1996-10-04  0:00 UTC (permalink / raw)



Norm Cohen says

> ">   begin
> >      ...
> >   exception
> >      ...
> >   at end
> >      < sequence of frame finalization statements >
> >   end"
>
> Interestingly, internally GNAT implements at end, but does not allow it
> to be mixed with an exception handler, and at end, unlike an exception
> handler, covers the associated declarations.

Both those differences detract from the value of "at end".


I don't think so. After all it is a trivial syntactic transformation to
go from whatever you have in mind to the semantics implemented by GNAT
(which corresponds to the standard GCC cleanup semantics).

The reason for not allowing at end and exceptions in the same scope was
simply for clarity, this makes it very clear what the semantics is whereas
if you have to allow both, then you have to answer questions like
what happens if an exception happens in the finalization?

The reason we cover the declarations is two-fold, first for almost all
internal uses of the construct (and of course it is ONLY an internal
use construct at the moment), this is more convenient, and second, as
I noted, it corresponds to the GCC cleanup notion.

But anyway, the first point I made is the critical one, you can transform
one semantics into the other trivially, so what's the issue?





^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Q. on Automatic Package Finalization
  1996-09-28  0:00 Robert Dewar
@ 1996-10-04  0:00 ` Norman H. Cohen
  1996-10-06  0:00   ` Robert Dewar
  0 siblings, 1 reply; 12+ messages in thread
From: Norman H. Cohen @ 1996-10-04  0:00 UTC (permalink / raw)



Robert Dewar wrote:
 
> Really the annoying thing is the restriction on controlled typs to the
> outer level. This really is not something that the compilre requires. We
> may provide some facility in GNAT to get around this restriction ...

Unfortunately, the restriction is necessary to prevent dangling
references:

   with Ada.Finalization; use Ada.Finalization;
   package Long_Lived is
      type Controlled_Pointer_Type is access Controlled'Class;
      Stale_Pointer_1, Stale_Pointer_2: Controlled_Pointer_Type;
   end Long_Lived;

   with Ada.Finalization, Long_Lived; use Ada.Finalization;
   procedure Local_Scope is
      Short_Lived_Variable: Integer := 0;
      package Nested_Finalization is
         type Nested_Controlled is new Controlled with null record; --
ILLEGAL!
         procedure Finalize (Object: in out Nested_Controlled);
      end Nested_Finalization;
      package body Nested_Finalization is
          procedure Finalize (Object: in out Nested_Controlled) is
          begin
             Short_Lived_Variable := Short_Lived_Variable + 1;
          end Finalize;
      end Nested_Finalization;
   begin
      Long_Lived.Stale_Pointer_1 := new
Nested_Finalization.Nested_Controlled;
      Long_Lived.Stale_Pointer_2 := new
Nested_Finalization.Nested_Controlled;
   end Local_Scope;

   with Long_Lived, Local_Scope;
   procedure Main is
   begin
      Local_Scope;
          -- Sets Stale_Pointer_1 and Stale_Pointer_2 to point to
objects of a 
          -- type Nested_Controlled that no longer exists upon return
from the call.
      Long_Lived.Stale_Pointer_1.all := Long_Lived.Stale_Pointer_2.all;
         -- Invokes the Finalize procedure for Stale_Pointer_1.all,
which increments
         --    Short_Lived_Variable, but Short_Lived_Variable no longer
exists!
   end Main;

Nonetheless, there are legitimate implementation-defined enhancements to
achieve the  effect of frame finalization that manipulates local
variables.

One approach would be a generic package Nested_Finalization whose
instances provide facilities identical to those of Ada.Finalization, but
using their own root types Controlled and Limited_Controlled and, like
Ada.Finalization, achieving the required effect through invisible
implementation magic.  Nested_Finalization could be instantiated inside
a subprogram, for example, and extended there:

   with Nested_Finalization;
   procedure Local_Scope is
      package Local_Finalization is new Nested_Finalization;
      package Frame_Finalization is
         type Frame_Finalization_Type is new
Local_Finalization.Controlled with ...;
            -- Legal because the parent type is at same accessibility
level.
         ...
         procedure Finalize (Object: in out Frame_Finalization_Type);
      end Frame_Finalization;
      ...
      Frame_Finalization_Object: Frame_Finalization_Type;
   begin 
      ...
   end Local_Scope;

A simpler alternative for frame finalization is the following generic
package:

   generic
      with procedure Finalize;
   package At_End;

Instantiation of this package within a frame's declarative part would,
through invisible implementation magic, cause the procedure Finalize to
be invoked upon exit from the frame:

   with At_End;
   procedure Local_Scope is
      ...
      procedure My_Finalize is
         ...
      end My_Finalize;
      package Frame_Finalization is new At_End(My_Finalize);
   begin
      ...
   end Local_Scope;

-- 
Norman H. Cohen
mailto:ncohen@watson.ibm.com
http://www.research.ibm.com/people/n/ncohen




^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Q. on Automatic Package Finalization
  1996-10-04  0:00 ` Norman H. Cohen
@ 1996-10-06  0:00   ` Robert Dewar
  0 siblings, 0 replies; 12+ messages in thread
From: Robert Dewar @ 1996-10-06  0:00 UTC (permalink / raw)



Norman Cohen says

"Unfortunately, the restriction is necessary to prevent dangling
references:"

Sure, but Ada allows dangling references in many situations, so I see no
reason to be *too* hard-nosed in absolutely forbidding this possibility,
provided that it is clear to the programmer what risks are there (I did
not put Unchecked_Access into the language :-)





^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~1996-10-06  0:00 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
1996-09-28  0:00 Q. on Automatic Package Finalization Robert Dewar
1996-10-04  0:00 ` Norman H. Cohen
1996-10-04  0:00   ` Robert Dewar
  -- strict thread matches above, loose matches on Subject: below --
1996-09-28  0:00 Robert Dewar
1996-10-04  0:00 ` Norman H. Cohen
1996-10-06  0:00   ` Robert Dewar
1996-09-22  0:00 david scott gibson
1996-09-23  0:00 ` Robert Dewar
1996-09-24  0:00   ` Norman H. Cohen
1996-09-24  0:00     ` Tucker Taft
1996-09-25  0:00   ` Jens Jakob Jensen
1996-09-25  0:00   ` Norman H. Cohen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox