Ada Programming/Types/limited

From Wikibooks, open books for an open world
Jump to navigation Jump to search


Limited Types[edit]

When a type is declared limited this means that objects of the type cannot be assigned values of the same type. An Object b of limited type LT cannot be copied into an object a of same type LT.

Additionally, there is no predefined equality operation for objects of a limited type.

The desired effects of declaring a type limited include prevention of shallow copying. Also, the (unique) identity of an object is retained: once declared, a name of a variable of type LT will continue to refer to the same object.

The following example will use a rather simplifying type Boat.

      type Boat  is  limited  private;

      function Choose
       (Load  : Sailors_Units;
        Speed : Sailors_Units)
         return  Boat;

      procedure Set_Sail (The_Boat :  in  out Boat);

When we declare a variable to be of type Boat, its name will denote one boat from then on. Boats will not be copied into one another.

The full view of a boat might be implemented as a record such as

      type Boat  is  limited  record
        Max_Sail_Area : Sailors_Units;
        Max_Freight   : Sailors_Units;
        Sail_Area     : Sailors_Units;
        Freight       : Sailors_Units;
      end  record;

The Choose function returns a Boat object depending on the parameters Load and Speed. If we now declare a variable of type Boat we will be better off Choosing an initial Boat (or else we might be dropping into uninitialized waters!). But when we do so, the initialization looks suspiciously like assignment which is not available with limited types:

   procedure Travel (People : Positive; Average_Speed : Sailors_Units)  is

     Henrietta : Boat :=   -- assignment?
          (Load  => People * Average_Weight * 1.5,
           Speed => Average_Speed * 1.5);

     Set_Sail (Henrietta);
   end Travel;

Fortunately, current Ada distinguishes initialization from copying. Objects of a limited type may be initialized by an initialization expression on the right of the delimiter :=.

(Just to prevent confusion: The Ada Reference Manual discriminates between assignment and assignment statement, where assignment is part of the assignment statement. An initialisation is of course an assignment which, for limited types, is done in place. An assignment statement involves copying, which is forbidden for limited types.)

Related to this feature are aggregates of limited types and “constructor functions” for limited types. Internally, the implementation of the Choose function will return a limited record. However, since the return type Boat is limited, there must be no copying anywhere. Will this work? A first attempt might be to declare a result variable local to Choose, manipulate result, and return it. The result object needs to be “transported” into the calling environment. But result is a variable local to Choose. When Choose returns, result will no longer be in scope. Therefore it looks like result must be copied but this is not permitted for limited types. There are two solutions provided by the language: extended return statements (see 6.5: Return Statements (Annotated)) and aggregates of limited types. The following body of Choose returns an aggregate of limited type Boat, after finding the initial values for its components.

      function Choose
       (Load  : Sailors_Units;
        Speed : Sailors_Units)
         return  Boat
        Capacity :  constant Sailors_Units := Capacity_Needed (Load);
         return Boat'
          (Max_Freight   => Capacity,
           Max_Sail_Area => Sail_Needed (Capacity),
           Freight       => Load,
           Sail_Area     => 0.0);
      end Choose;

The object that is returned is at the same time the object that is to have the returned value. The function therefore initializes Henrietta in place.

In parallel to the predefined type Ada.Finalization.Controlled, Ada provides the type Limited_Controlled in the same package. It is a limited version of the former.

Initialising Limited Types[edit]

A few methods to initialise such types are presented.

 package Limited_Private_Samples  is

   type Uninitialised   is  limited  private;
   type Preinitialised  is  limited  private;

   type Dynamic_Initialisation  is  limited  private;
   function Constructor (X: Integer)  -- any kind of parameters
     return Dynamic_Initialisation;

   type Needs_Constructor (<>)  is  limited  private;
   function Constructor (X: Integer)  -- any kind of parameters
     return Needs_Constructor;


   type Uninitialised  is  record
    I: Integer;
   end  record;

   type Preinitialised  is  record
    I: Integer := 0;  -- can also be a function call
   end  record;

   type Void  is  null  record;
   function Constructor (Object:  access Dynamic_Initialisation)  return Void;

   type Dynamic_Initialisation  is  limited  record
    Hook: Void := Constructor (Dynamic_Initialisation' Access);
    Bla : Integer;  -- any needed components
   end  record;

   type Needs_Constructor  is  record
    I: Integer;
   end  record;

 end Limited_Private_Samples;
 package  body Limited_Private_Samples  is

   function Constructor (Object:  access Dynamic_Initialisation)  return Void  is
    Object.Bla := 5;  -- may be any value only known at run time
     return ( null  record);
   end Constructor;

   function Constructor (X: Integer)  return Dynamic_Initialisation  is
     return (Hook => ( null  record),
            Bla  => 42);
   end Constructor;

   function Constructor (X: Integer)  return Needs_Constructor  is
     return (I => 42);
   end Constructor;

 end Limited_Private_Samples;
  with Limited_Private_Samples;
  use  Limited_Private_Samples;
  procedure Try  is
   U: Uninitialised;   -- very bad
   P: Preinitialised;  -- has initial value (good)
   D1: Dynamic_Initialisation;  -- has initial value (good)
   D2: Dynamic_Initialisation := Constructor (0);  -- Ada 2005 initialisation
   D3: Dynamic_Initialisation  renames Constructor (0);  -- already Ada 95
   -- I: Needs_Constructor;  -- Illegal without initialisation
   N: Needs_Constructor := Constructor (0);  -- Ada 2005 initialisation
  end Try;

Note that D3 is a constant, whereas all others are variables.

Also note that the initial value that is defined for the component of Preinitialised is evaluated at the time of object creation, i.e. if an expression is used instead of the literal, the value can be run-time dependent.

X, Y: Preinitialised;

In this declaration of two objects, the initial expression will be evaluated twice and can deliver different values, because it is equivalent to the sequence:[1]

X: Preinitialised;
Y: Preinitialised;

So X is initialised before Y.

See also[edit]

Ada 95 Reference Manual[edit]

Ada 2005 Reference Manual[edit]

Ada Quality and Style Guide[edit]


  1. ISO/IEC 8652:2007. "3.3.1 Object Declarations (7)". Ada 2005 Reference Manual. "Any declaration [...] with more than one defining_identifier is equivalent to a series of declarations each containing one defining_identifier from the list, [...] in the same order as the list."