5.7 Controlled Type Example

[ Table of Contents ] Prev ] Chapter Overview ] Next ] [ Glossary/Index ]

A controlled type is a special kind of tagged type that gives the programmer extra control over what happens at certain times -- such as when an object of the type is created, or when the object is about to go out of existence. A controlled type is created by deriving it from one of two predefined types exported by the package Ada.Finalization. For example, one can write:

type My_Type_1 is new Ada.Finalization.Controlled;
type My_Type_2 is new Ada.Finalization.Limited_Controlled;

My_Type_1 inherits three operations called Initialize, Adjust and Finalize. My_Type_2 inherits two operations called Initialize and Finalize. Initialize is automatically called when a controlled object is created. Adjust is automatically called as the last step of an assignment to a controlled object. Finalize is automatically called when a controlled object is about to go out of existence. The default (inherited) versions of these procedures do nothing, but the programmer can override any of them to perform some desired action. (A common motivation for the use of Finalize is to prevent "memory leak" in real-time systems. This involves the use of a predefined procedure called Ada.Unchecked_Deallocation. We will not illustrate such techniques in this introductory volume.)

Example Program with Initialize and Finalize of Controlled Objects

This program creates a controlled type, Bomber, derived from Ada.Finalization.Controlled (from the predefined environment). There are two exported operations and two private operations, Initialize and Finalize. The test procedure has an inner procedure, Bomb_With_Local_Objects, that declares a local access-to-Bomber type and value. The outer procedure declares a global access-to-Bomber type and values. The two bombing loops behave differently with respect to finalization (see the code and further discussion below).

Im5-8.gif (5652 bytes)

Careful study of the code and sample output given below reveals the following order of events. Bomber 1 and Bomber 2 are created and initialized first, but finalized last (in reverse order), because they are associated with the global access-to-bomber type and don't go out of existence until the outer procedure is ready to quit. Bomber 3 is created and finalized before Bomber 4 is created and finalized. These two are associated with the local access-to-bomber type and each ceases to exist at the end of each call to the inner procedure.

Source Code Listing

-------------------------------------------------------------------
------  Bombers  --------------------------------------------------
-------------------------------------------------------------------
--  This package exports a controlled type, Bomber, that has two 
--  visible operations and two private operations. Initialize and 
--  Finalize (the private operations) are used to keep track of how 
--  many bombers have been created so far and how many are still 
--  "in play". Initialize also assigns a number to each bomber. 
-------------------------------------------------------------------
with Ada.Finalization;
package Bombers is  
  type Lat_Type is range -90..90;           
  type Lon_Type is range -180..180;
  type Hdg_Type is mod 360;
  type Alt_Type is range 0..100000;   
  type Bomber is new Ada.Finalization.Controlled with private;
    
  procedure Reset_State(B   : in out Bomber; -- primitive operation 
                        Lat : in Lat_Type;
                        Lon : in Lon_Type;
                        Hdg : in Hdg_Type;
                        Alt : in Alt_Type);
  procedure Deploy_Weapon(B  : in Bomber);   -- primitive operation
private  
  type Bomber is new Ada.Finalization.Controlled with 
    record
      Number    : Natural  := 0;
      Latitude  : Lat_Type := 0;
      Longitude : Lon_Type := 0;
      Heading   : Hdg_Type := 0;
      Altitude  : Alt_Type := 30000;
    end record; 
    procedure Initialize(B : in out Bomber);  -- override operation
    procedure Finalize  (B : in out Bomber);  -- override operation
end Bombers;
-------------------------------------------------------------------
with Ada.Text_IO; use Ada.Text_IO;
package body Bombers is
  Next_Number     : Natural := 0;        -- increment in Initialize
  Number_In_Play  : Natural := 0;        -- increment in Initialize,
                                           --  decrement in Finalize
  --------------------------------------------  
  procedure Reset_State(B   : in out Bomber; 
                        Lat : in Lat_Type;
                        Lon : in Lon_Type;
                        Hdg : in Hdg_Type;
                        Alt : in Alt_Type) is
  begin                     
    B.Latitude  := Lat;
    B.Longitude := Lon;
    B.Heading   := Hdg;
    B.Altitude  := Alt;  
  end Reset_State;      
  ------------------------------------------
  procedure Deploy_Weapon(B  : in Bomber) is
  begin
    Put_line("Bomber " & Integer'Image(B.Number) &
             " releases bomb at" & 
             " Lat = " & Integer'Image(Integer(B.Latitude)) &
             ", Lon = " & Integer'Image(Integer(B.Longitude)) &
             ", Hdg = " & Integer'Image(Integer(B.Heading)) &
             ", Alt = " & Integer'Image(Integer(B.Altitude)));    
  end Deploy_Weapon;
  --------------------------------------------------
  procedure Initialize(B : in out Bomber) is
  begin
    Next_Number    := Next_Number + 1;
    Number_In_Play := Number_In_Play + 1;
    B.Number       := Next_Number;
    Put_Line("Bomber " & Integer'Image(B.Number) &
             " initialized");    
  end Initialize;    
  --------------------------------------------------
  procedure Finalize(B : in out Bomber) is
  begin
    Number_In_Play := Number_In_Play - 1;   
    Put_Line("Bomber " & Integer'Image(B.Number) &
             " finalized" & ", Number_In_Play = " &
             Integer'Image(Number_In_Play));       
  end Finalize;
end Bombers;
-------------------------------------------------------------------
-------- Test_Controlled ------------------------------------------
-------------------------------------------------------------------
--  This procedure tests the controlled type, Bomber, using two 
--  loops. One uses a local access type and the other uses a global 
--  access type. 
-------------------------------------------------------------------
with Bombers, Ada.Text_IO, Ada.Integer_Text_IO; 
use  Bombers, Ada.Text_IO, Ada.Integer_Text_IO;
procedure Test_Controlled is  
  Ch    : Character; Data  : Integer;
  B_Lat : Lat_Type;  B_Lon : Lon_Type; 
  B_Hdg : Hdg_Type;  B_Alt : Alt_Type;
  type Bptr1_Type is access all Bomber;      -- global access type
  Bptr1 : array (1..20) of Bptr1_Type;
  ---------------------------------------
  procedure Bomb_With_Local_Objects is
    type Bptr2_Type is access all Bomber;    -- local access type
    Bptr2 : Bptr2_Type;  
  begin
    Bptr2 := new Bomber;                     -- auto initialization
    Reset_State(Bptr2.all, B_Lat, B_Lon, B_Hdg, B_Alt);
    Deploy_Weapon(Bptr2.all); 
  end Bomb_With_Local_Objects;               -- auto finalization
  ---------------------------------------
begin
  Put("Enter bombing latitude (-90..90) > ");
  Get(Data); B_Lat := Lat_Type(Data);  
  Put("Enter bombing longitude (-90..90) > ");
  Get(Data); B_Lon := Lon_Type(Data);
  Put("Enter bombing heading (0..359) > ");
  Get(Data); B_Hdg := Hdg_Type(Data);
  Put("Enter bombing altitude (5000..40000) > ");
  Get(Data); B_Alt := Alt_Type(Data); 
  New_Line;
  
  for I in 1..2 loop                         -- first bombing loop
    Bptr1(I) := new Bomber;                  -- auto initialization
    Reset_State(Bptr1(I).all, B_Lat, B_Lon, B_Hdg, B_Alt);
    Deploy_Weapon(Bptr1(I).all); 
  end loop;                                  -- no finalization
  
  Put("Enter bombing heading (0..359) > ");
  Get(Data); B_Hdg := Hdg_Type(Data);
  
  loop                                       -- second bombing loop
    Put("Enter b or q (Bomb or Quit) > ");
    Get(Ch);
    exit when Ch = 'q';
    if Ch = 'b' then
      Bomb_With_Local_Objects;
    else
      Put_Line("Invalid input");
    end if;
  end loop;                      
end Test_Controlled;      -- finalization for bombers in first loop
-------------------------------------------------------------------

Here is a sample output from the above program:

  Enter bombing latitude (-90..90) > 30 
  Enter bombing longitude (-90..90) > -50
  Enter bombing heading (0..359) > 90
  Enter bombing altitude (5000..40000) > 15000

  Bomber  1 initialized
  Bomber  1 releases bomb at Lat = 30, Lon = -50, Hdg = 90, Alt = 15000
  Bomber  2 initialized
  Bomber  2 releases bomb at Lat = 30, Lon = -50, Hdg = 90, Alt = 15000
  Enter bombing heading (0..359) > 95
  Enter b or q (Bomb or Quit) > b  
  Bomber  3 initialized
  Bomber  3 releases bomb at Lat = 30, Lon = -50, Hdg = 95
  Bomber  3 finalized, Number_In_Play = 2
  Enter b or q (Bomb or Quit) > b
  Bomber  4 initialized
  Bomber  4 releases bomb at Lat = 30, Lon = -50, Hdg = 95, Alt = 15000
  Bomber  4 finalized, Number_In_Play = 2
  Enter b or q (Bomb or Quit) > q
  Bomber  2 finalized, Number_In_Play = 1
  Bomber  1 finalized, Number_In_Play = 0

Related Topics

5.2 Type Extension B.2 Package Ada and Children

[ Back to top of pagePrev ] Next ]