2 Synthesis‎ > ‎Computing‎ > ‎Programming‎ > ‎Ada‎ > ‎Ada Language‎ > ‎

Data

Data Types

Every object in the language has a type, which characterizes a set of values and a set of applicable operations. The main classes of types are elementary types (comprising enumeration, numeric, and access types) and composite types (including array and record types).  
  • An enumeration type defines an ordered set of distinct enumeration literals, for example a list of states or an alphabet of characters. The enumeration types Boolean, Character, Wide_Character, and Wide_Wide_Character are predefined.  
  • Numeric types provide a means of performing exact or approximate numerical computations. Exact computations use integer types, which denote sets of consecutive integers. Approximate computations use either fixed point types, with absolute bounds on the error, or floating point types, with relative bounds on the error. The numeric types Integer, Float, and Duration are predefined.  
  • Composite types allow definitions of structured objects with related components. The composite types in the language include arrays and records. An array is an object with indexed components of the same type. A record is an object with named components of possibly different types. Task and protected types are also forms of composite types. The array types String, Wide_String, and Wide_Wide_String are predefined.  
  • Record, task, and protected types may have special components called discriminants which parameterize the type. Variant record structures that depend on the values of discriminants can be defined within a record type.  
  • Access types allow the construction of linked data structures. A value of an access type represents a reference to an object declared as aliased or to an object created by the evaluation of an allocator. Several variables of an access type may designate the same object, and components of one object may designate the same or other objects. Both the elements in such linked data structures and their relation to other elements can be altered during program execution. Access types also permit references to subprograms to be stored, passed as parameters, and ultimately dereferenced as part of an indirect call.  
  • Private types permit restricted views of a type. A private type can be defined in a package so that only the logically necessary properties are made visible to the users of the type. The full structural details that are externally irrelevant are then only available within the package and any child units.  
  • Derived types - From any type a new type may be defined by derivation. A type, together with its derivatives (both direct and indirect) form a derivation class. Class-wide operations may be defined that accept as a parameter an operand of any type in a derivation class. For record and private types, the derivatives may be extensions of the parent type. Types that support these object-oriented capabilities of class-wide operations and type extension must be tagged, so that the specific type of an operand within a derivation class can be identified at run time. When an operation of a tagged type is applied to an operand whose specific type is not known until run time, implicit dispatching is performed based on the tag of the operand.  
  • Interface types provide abstract models from which other interfaces and types may be composed and derived. This provides a reliable form of multiple inheritance. Interface types may also be implemented by task types and protected types thereby enabling concurrent programming and inheritance to be merged.  
  • The concept of a type is further refined by the concept of a subtype, whereby a user can constrain the set of allowed values of a type. Subtypes can be used to define subranges of scalar types, arrays with a limited set of index values, and records and private types with particular discriminant values. 

Basic Declarations

Examples of variable declarations
 
Count, Sum  : Integer;
Size        : Integer range 0 .. 10_000 := 0;
Sorted      : Boolean := False;
Color_Table : array(1 .. Max) of Color;
Option      : Bit_Vector(1 .. 10) := (others => True);
Hello       : aliased String := "Hi, world.";
θ, φ        : Float range -π .. +π;
 
Examples of constant declarations
 
      Limit     : constant Integer := 10_000;
      Low_Limit : constant Integer := Limit/10;
      Tolerance : constant Real := Dispersion(1.15);
      Hello_Msg : constant access String := Hello'Access; -- see 3.10.

Examples of number declarations 
 
      Two_Pi        : constant := 2.0*Ada.Numerics.Pi;   -- a real number(see A.5
      )
 
      Max           : constant := 500;                   -- an integer number
      Max_Line_Size : constant := Max/6;                 -- the integer 83
      Power_16      : constant := 2**16;                 -- the integer 65_536
      One, Un, Eins : constant := 1;                     -- three different names for 1


Examples of string declarations:
 
      Stars      : String(1 .. 120) := (1 .. 120 => '*' );
      Question   : constant String  := "How many characters?";
      -- Question'First = 1, Question'Last = 20
      -- Question'Length = 20 (the number of characters)

      Ask_Twice  : String  := Question & Question;                 
      -- constrained to (1..40)
      Ninety_Six : constant Roman   := "XCVI";                     
      -- see 3.5.2 and 3.6

Example of a multiple object declaration:
 
      --  the multiple object declaration 
 
      John, Paul : not null Person_Name := new Person(Sex => M);  --  see 3.10.1
 
      --  is equivalent to the two single object declarations in the order given
 
      John : not null Person_Name := new Person(Sex => M);
      Paul : not null Person_Name := new Person(Sex => M);

Array Declaration


Name  : array (0 .. 30) of Character; -- OR
Name : String (1 .. 30);
Track : array (0 .. 2) of Integer;
DblA : array (0 .. 2) of array (0 .. 9) of Integer; -- OR
DblA : array (0 .. 2,0 .. 9) of Integer;
Init : array (0 .. 2) of Integer := (0, 1, 2);
type Name_Type is array (0 .. 30) of Character;
track(2) := 1;
dbla(0,3) := 2;



Examples of array declarations including an index constraint:
 
      Board     : Matrix(1 .. 8,  1 .. 8);  --  see 3.6
      Rectangle : Matrix(1 .. 20, 1 .. 30);
      Inverse   : Matrix(1 .. N,  1 .. N);  --  N need not be static 
 
      Filter    : Bit_Vector(0 .. 31);
 
Example of array declaration with a constrained array subtype:
 
      My_Schedule : Schedule;  --  all arrays of type Schedule have the same bounds
 
Example of record type with a component that is an array:
 
      type Var_Line(Length : Natural) is
         record
            Image : String(1 .. Length);
         end record;
 
      Null_Line : Var_Line(0);  --  Null_Line.Image is a null array

Examples of ranges:
 
      -10 .. 10
      X .. X + 1
      0.0 .. 2.0*Pi
      Red .. Green     -- see 3.5.1
      1 .. 0           -- a null range
      Table'Range      -- a range attribute reference (see 3.6)
 

 
Examples of object declarations with array type definitions:
 
      Grid      : array(1 .. 80, 1 .. 100) of Boolean;
      Mix       : array(Color range Red .. Green) of Boolean;
      Msg_Table : constant array(Error_Code) of access constant String :=
            (Too_Big => new String'("Result too big"), Too_Small => ...);
      Page      : array(Positive range <>) of Line :=  --  an array of arrays
        (1 | 50  => Line'(1 | Line'Last => '+', others => '-'),  -- see 4.3.3
         2 .. 49 => Line'(1 | Line'Last => '|', others => ' '));
          -- Page is constrained by its initial value to (1..50)

Type Declarations

Examples of type declarations:
 
      type Color  is (White, Red, Yellow, Green, Blue, Brown, Black);
      type Column is range 1 .. 72;
      type Table  is array(1 .. 10) of Integer;

Example of a character type:
 
      type Roman_Digit is ('I', 'V', 'X', 'L', 'C', 'D', 'M');

The part after the word "is" is called the type definition.


Examples of type declarations with unconstrained array definitions:
 
      type Vector     is array(Integer  range <>) of Real;
      type Matrix     is array(Integer  range <>, Integer range <>) of Real;
      type Bit_Vector is array(Integer  range <>) of Boolean;
      type Roman      is array(Positive range <>) of Roman_Digit; -- see 3.5.2
 
Examples of type declarations with constrained array definitions:
 
      type Table    is array(1 .. 10) of Integer;
      type Schedule is array(Day) of Boolean;
      type Line     is array(1 .. Max_Line_Size) of Character;


Examples of subtype declarations:
 
      subtype Rainbow   is Color range Red .. Blue;
      subtype Red_Blue  is Rainbow;
      subtype Int       is Integer;
      subtype Small_Int is Integer range -10 .. 10;
      subtype Up_To_K   is Column range 1 .. K;            --  see 3.2.1
      subtype Square    is Matrix(1 .. 10, 1 .. 10);       --  see 3.6
      subtype Male      is Person(Sex => M);               --  see 3.10.1
      subtype Binop_Ref is not null Binop_Ptr;             --  see 3.10

Examples of derived type declarations:
 
      type Local_Coordinate is new Coordinate;   --  two different types
      type Midweek is new Day range Tue .. Thu;  --  see 3.5.1
      type Counter is new Positive;              --  same range as Positive 
 
      type Special_Key is new Key_Manager.Key;   --  see 7.3.1
        -- the inherited subprograms have the following specifications: 
        --         procedure Get_Key(K : out Special_Key);
        --         function "<"(X,Y : Special_Key) return Boolean;


Examples of attributes of discrete subtypes:
Note that these are comments not syntax!
 
      --  For the types and subtypes declared in subclause 3.5.1
       the following hold: 
 
      --  Color'First   = White,   Color'Last   = Black
      --  Rainbow'First = Red,     Rainbow'Last = Blue
 
      --  Color'Succ(Blue) = Rainbow'Succ(Blue) = Brown
      --  Color'Pos(Blue)  = Rainbow'Pos(Blue)  = 4
      --  Color'Val(0)     = Rainbow'Val(0)     = White

Examples of record type declarations:
 
      type Date is
         record
            Day   : Integer range 1 .. 31;
            Month : Month_Name;
            Year  : Integer range 0 .. 4000;
         end record;
 
      type Complex is
         record
            Re : Real := 0.0;
            Im : Real := 0.0;
         end record;
 
Examples of record variables:
 
      Tomorrow, Yesterday : Date;
      A, B, C : Complex;
 
      -- both components of A, B, and C are implicitly initialized to zero


Declaration of Subtypes

Examples of enumeration types and subtypes:
 
      type Day    is (Mon, Tue, Wed, Thu, Fri, Sat, Sun);
      type Suit   is (Clubs, Diamonds, Hearts, Spades);
      type Gender is (M, F);
      type Level  is (Low, Medium, Urgent);
      type Color  is (White, Red, Yellow, Green, Blue, Brown, Black);
      type Light  is (Red, Amber, Green); -- Red and Green are overloaded
 
      type Hexa   is ('A', 'B', 'C', 'D', 'E', 'F');
      type Mixed  is ('A', 'B', '*', B, None, '?', '%');
 
      subtype Weekday is Day   range Mon .. Fri;
      subtype Major   is Suit  range Hearts .. Spades;
      subtype Rainbow is Color range Red .. Blue;  --  the Color Red, not the Light

Examples of range constraints:
 
      range -999.0 .. +999.0
      range S'First+1 .. S'Last-1

Examples of integer types and subtypes:
 
      type Page_Num  is range 1 .. 2_000;
      type Line_Size is range 1 .. Max_Line_Size;
 
      subtype Small_Int   is Integer   range -10 .. 10;
      subtype Column_Ptr  is Line_Size range 1 .. 10;
      subtype Buffer_Size is Integer   range 0 .. Max;
 
      type Byte        is mod 256; -- an unsigned byte
      type Hash_Index  is mod 97;  -- modulus is prime
 
Examples of floating point types and subtypes:
 
      type Coefficient is digits 10 range -1.0 .. 1.0;
      type Real is digits 8;
      type Mass is digits 7 range 0.0 .. 1.0E35;
      subtype Probability is Real range 0.0 .. 1.0;   --   a subtype with a smaller range
 

Examples of fixed point types and subtypes:
 
      type Volt is delta 0.125 range 0.0 .. 255.0;
 
      -- A pure fraction which requires all the available
        -- space in a word can be declared as the type Fraction:
      type Fraction is delta System.Fine_Delta range -1.0 .. 1.0;
        -- Fraction'Last = 1.0 - System.Fine_Delta
 
      type Money is delta 0.01 digits 15;  -- decimal fixed point
      subtype Salary is Money digits 10;
        -- Money'Last = 10.0**13 - 0.01, Salary'Last = 10.0**8 - 0.01


Discriminated types


Examples of discriminated types:
 
      type Buffer(Size : Buffer_Size := 100)  is        -- see 3.5.4
         record
            Pos   : Buffer_Size := 0;
            Value : String(1 .. Size);
         end record;
 
      type Matrix_Rec(Rows, Columns : Integer) is
         record
            Mat : Matrix(1 .. Rows, 1 .. Columns);       -- see 3.6
         end record;
 
      type Square(Side : Integer) is new
         Matrix_Rec(Rows => Side, Columns => Side);
 
      type Double_Square(Number : Integer) is
         record
            Left  : Square(Number);
            Right : Square(Number);
         end record;
 
      task type Worker(Prio : System.Priority; Buf : access Buffer) is
         -- discriminants used to parameterize the task type (see 9.1)
         pragma Priority(Prio);  -- see D.1
         entry Fill;
         entry Drain;
      end Worker;



Example of record type with a variant part:
 
      type Device is (Printer, Disk, Drum);
      type State  is (Open, Closed);
 
      type Peripheral(Unit : Device := Disk) is
         record
            Status : State;
            case Unit is
               when Printer =>
                  Line_Count : Integer range 1 .. Page_Size;
               when others =>
                  Cylinder   : Cylinder_Index;
                  Track      : Track_Number;
               end case;
            end record;

When a variable of type Peripheral is declared parameter of type Device should be passed in. if none is passed then the default is Disk. Unit will contain the Device value. 


Examples of record subtypes:
 
      subtype Drum_Unit is Peripheral(Drum);
      subtype Disk_Unit is Peripheral(Disk);
 
      Examples of constrained record variables:
 
      Writer   : Peripheral(Unit  => Printer);
      Archive  : Disk_Unit;

Examples of tagged record types:
 
32    type Point is tagged
        record
          X, Y : Real := 0.0;
        end record;
 
33    type Expression is tagged null record;
        -- Components will be added by each extension



 Examples of record extensions (of types defined above in 3.9):
 
11    type Painted_Point is new Point with
        record
          Paint : Color := White;
        end record;
          -- Components X and Y are inherited
 
12    Origin : constant Painted_Point := (X | Y => 0.0, Paint => Black);
 
13    type Literal is new Expression with
        record                 -- a leaf in an Expression tree
          Value : Real;
        end record;
 
14    type Expr_Ptr is access all Expression'Class;
                                     -- see 3.10
 
15    type Binary_Operation is new Expression with
        record                 -- an internal node in an Expression tree
          Left, Right : Expr_Ptr;
        end record;
 
16    type Addition is new Binary_Operation with null record;
      type Subtraction is new Binary_Operation with null record;
        -- No additional components needed for these extensions
 
17    Tree : Expr_Ptr :=         -- A tree representation of "5.0 + (13.0-7.0)"
         new Addition'(
            Left  => new Literal'(Value => 5.0),
            Right => new Subtraction'(
               Left  => new Literal'(Value => 13.0),
               Right => new Literal'(Value => 7.0)));


Examples of access-to-object types:


  type List_Node;  -- An incomplete type declaration.
type List_Node_Access is access List_Node;
type List_Node is
record
Data : Integer;
Next : List_Node_Access; -- Next Node in the list.
end record;



 
22/2  type Peripheral_Ref is not null access Peripheral;  --  see 3.8.1
      type Binop_Ptr is access all Binary_Operation'Class;
                                                 -- general access-to-class-wide, see 3.9.1
 
Example of an access subtype:
 
24    subtype Drum_Ref is Peripheral_Ref(Drum);  --  see 3.8.1
 
Example of an access-to-subprogram type:
 
26    type Message_Procedure is access procedure (M : in String := "Error!");
      procedure Default_Message_Procedure(M : in String);
      Give_Message : Message_Procedure := Default_Message_Procedure'Access;
      ...
      procedure Other_Procedure(M : in String);
      ...
      Give_Message := Other_Procedure'Access;
      ...
      Give_Message("File not found.");  -- call with parameter (.all is optional)
      Give_Message.all;                 -- call with no parameters



Example of a recursive type:
 
15    type Cell;  --  incomplete type declaration
      type Link is access Cell;
 
16    type Cell is
         record
            Value  : Integer;
            Succ   : Link;
            Pred   : Link;
         end record;
 
17    Head   : Link  := new Cell'(0, null, null);
      Next   : Link  := Head.Succ;
 
Examples of mutually dependent access types:
 
19/2  type Person(<>);    -- incomplete type declaration
      type Car is tagged; -- incomplete type declaration
 
20/2  type Person_Name is access Person;
      type Car_Name    is access all Car'Class;
 
21/2  type Car is tagged
         record
            Number  : Integer;
            Owner   : Person_Name;
         end record;
 
22    type Person(Sex : Gender) is
         record
            Name     : String(1 .. 20);
            Birth    : Date;
            Age      : Integer range 0 .. 130;
            Vehicle  : Car_Name;
            case Sex is
               when M => Wife           : Person_Name(Sex => F);
               when F => Husband        : Person_Name(Sex => M);
            end case;
         end record;
 
23    My_Car, Your_Car, Next_Car : Car_Name := new Car;  -- see 4.8
      George : Person_Name := new Person(M);
         ...
      George.Vehicle := Your_Car;

Other


Example of use of the Access attribute:
 
41    Martha : Person_Name := new Person(F);       -- see 3.10.1
      Cars   : array (1..2) of aliased Car;
         ...
      Martha.Vehicle := Cars(1)'Access;
      George.Vehicle := Cars(2)'Access;



Example of an abstract type representing a set of natural numbers:
 
15    package Sets is
          subtype Element_Type is Natural;
          type Set is abstract tagged null record;
          function Empty return Set is abstract;
          function Union(Left, Right : Set) return Set is abstract;
          function Intersection(Left, Right : Set) return Set is abstract;
          function Unit_Set(Element : Element_Type) return Set is abstract;
          procedure Take(Element : out Element_Type;
                         From : in out Set) is abstract;
      end Sets;

      NOTES
 
16    78  Notes on the example: Given the above abstract type, one could then
      derive various (nonabstract) extensions of the type, representing
      alternative implementations of a set. One might use a bit vector, but
      impose an upper bound on the largest element representable, while
      another might use a hash table, trading off space for flexibility.
 
 
3.9.4 Interface Types
 
 
1/2   An interface type is an abstract tagged type that provides a restricted
form of multiple inheritance. A tagged type, task type, or protected type may
have one or more interface types as ancestors.


Example of a limited interface and a synchronized interface extending it:
 
21/2  type Queue is limited interface;
      procedure Append(Q : in out Queue; Person : in Person_Name) is abstract;
      procedure Remove_First(Q      : in out Queue;
                             Person : out Person_Name) is abstract;
      function Cur_Count(Q : in Queue) return Natural is abstract;
      function Max_Count(Q : in Queue) return Natural is abstract;
      -- See 3.10.1 for Person_Name.
 
22/2  Queue_Error : exception;
      -- Append raises Queue_Error if Count(Q) = Max_Count(Q)
      -- Remove_First raises Queue_Error if Count(Q) = 0
 
23/2  type Synchronized_Queue is synchronized interface and Queue; -- see 9.11
      procedure Append_Wait(Q      : in out Synchronized_Queue;
                            Person : in Person_Name) is abstract;
      procedure Remove_First_Wait(Q      : in out Synchronized_Queue;
                                  Person : out Person_Name) is abstract;
 
24/2  ...
 
25/2  procedure Transfer(From   : in out Queue'Class;
                         To     : in out Queue'Class;
                         Number : in     Natural := 1) is
         Person : Person_Name;
      begin
         for I in 1..Number loop
            Remove_First(From, Person);
            Append(To, Person);
         end loop;
      end Transfer;
 
26/2  This defines a Queue interface defining a queue of people. (A similar
design could be created to define any kind of queue simply by replacing
Person_Name by an appropriate type.) The Queue interface has four dispatching
operations, Append, Remove_First, Cur_Count, and Max_Count. The body of a
class-wide operation, Transfer is also shown. Every non-abstract extension of
Queue must provide implementations for at least its four dispatching
operations, as they are abstract. Any object of a type derived from Queue may
be passed to Transfer as either the From or the To operand. The two operands
need not be of the same type in any given call.
 
27/2  The Synchronized_Queue interface inherits the four dispatching
operations from Queue and adds two additional dispatching operations, which
wait if necessary rather than raising the Queue_Error exception. This
synchronized interface may only be implemented by a task or protected type,
and as such ensures safe concurrent access.
 
Example use of the interface:
 
29/2  type Fast_Food_Queue is new Queue with record ...;
      procedure Append(Q : in out Fast_Food_Queue; Person : in Person_Name);
      procedure Remove_First(Q : in out Fast_Food_Queue; Person : in Person_Name);
      function Cur_Count(Q : in Fast_Food_Queue) return Natural;
      function Max_Count(Q : in Fast_Food_Queue) return Natural;
 
30/2  ...
 
31/2  Cashier, Counter : Fast_Food_Queue;
 
32/2  ...
      -- Add George (see 3.10.1) to the cashier's queue:
      Append (Cashier, George);
      -- After payment, move George to the sandwich counter queue:
      Transfer (Cashier, Counter);
      ...
 
33/2  An interface such as Queue can be used directly as the parent of a new
type (as shown here), or can be used as a progenitor when a type is derived.
In either case, the primitive operations of the interface are inherited. For
Queue, the implementation of the four inherited routines must be provided.
Inside the call of Transfer, calls will dispatch to the implementations of
Append and Remove_First for type Fast_Food_Queue.
 
34/2  Example of a task interface:
 
35/2  type Serial_Device is task interface;  -- see 9.1
      procedure Read (Dev : in Serial_Device; C : out Character) is abstract;
      procedure Write(Dev : in Serial_Device; C : in  Character) is abstract;
 
36/2  The Serial_Device interface has two dispatching operations which are
intended to be implemented by task entries (see 9.1).




Comments