Ada Programming/Types/record



A record is a composite type that groups one or more fields. A field can be of any type, even a record.

Ada. Time-tested, safe and secure.
Ada. Time-tested, safe and secure.

Basic record

edit
 type Basic_Record is
    record
       A : Integer;
    end record;

Null record

edit

The null record is when a type without data is needed. There are two ways to declare a null record:

type Null_Record is
   record
      null;
   end record; 
type Null_Record is null record;

For the compiler they are the same. However, programmers often use the first variant if the type is not finished yet to show that they are planning to expand the type later, or they usually use the second if the (tagged) record is a base class in object oriented programming.

Record Values

edit

Values of a record type can be specified using a record aggregate, giving a list of named components thus

  A_Basic_Record       : Basic_Record         := Basic_Record'(A => 42);
  Another_Basic_Record : Basic_Record         := (A => 42);
  Nix                  : constant Null_Record := (null record);

Given a somewhat larger record type,

  type Car is record
     Identity       : Long_Long_Integer;
     Number_Wheels  : Positive range 1 .. 10;
     Paint          : Color;
     Horse_Power_kW : Float range 0.0 .. 2_000.0;
     Consumption    : Float range 0.0 .. 100.0;
  end record;

a value may be specified using positional notation, that is, specifying a value for each record component in declaration order

  BMW : Car := (2007_752_83992434, 5, Blue, 190.0, 10.1);

However, naming the components of a Car aggregate offers a number of advantages.

  1. Easy identification of which value is used for which component. (After all, named components are the raison d'être of records.)
  2. Reordering the components is allowed—you only have to remember the component names, not their position.
  3. Improved compiler diagnostic messages.

Reordering components is possible because component names will inform the compiler (and the human reader!) of the intended value associations. Improved compiler messages are also in consequence of this additional information passed to the compiler. While an omitted component will always be reported due to Ada's coverage rules, messages can be much more specific when there are named associations. Considering the Car type from above, suppose a programmer by mistake specifies only one of the two floating point values for BMW in positional notation. The compiler, in search of another component value, will then not be able to decide whether the specified value is intended for Horse_Power_kW or for Consumption. If the programmer instead uses named association, say Horse_Power_kW => 190.0, it will be clear which other component is missing.

  BMW : Car :=
    (Identity       => 2007_752_83992434,
     Number_Wheels  => 5,
     Horse_Power_kW => 190.0,
     Consumption    => 10.1,
     Paint          => Blue);

In order to access a component of a record instance, use the dot delimiter (.), as in BMW.Number_Wheels.

Discriminated record

edit
 type Discriminated_Record (Size : Natural) is 
    record
       A : String (1 .. Size);
    end record;
 
 ...
 
 Item : Discriminated_Record := (Size => Value'Length, A => Value);

Variant record

edit

The variant record is a special type of discriminated record where the presence of some components depend on the value of the discriminant.

 type Traffic_Light is (Red, Yellow, Green);

 type Variant_Record (Option : Traffic_Light) is 
    record
       -- common components
       
       case Option is
          when Red =>
             -- components for red
          when Yellow =>
             -- components for yellow
          when Green =>
             -- components for green
       end case;
    end record;

Mutable and immutable variant records

edit

You can declare variant record types such that its discriminant, and thus its variant structure, can be changed during the lifetime of the variable. Such a record is said to be mutable. When "mutating" a record, you must assign all components of the variant structure which you are mutating at once, replacing the record with a complete variant structure. Although a variant record declaration may allow objects of its type to be mutable, there are certain restrictions on whether the objects will be mutable. Reasons restricting an object from being mutable include:

  • the object is declared with a discriminant (see Immutable_Traffic_Light below)
  • the object is aliased (either by use of aliased in the object declaration, or by allocation on the heap using new)


 type Traffic_Light is (Red, Yellow, Green);

 type Mutable_Variant_Record (Option : Traffic_Light := Red) is      -- the discriminant must have a default value
    record
       -- common components
       Location : Natural;
       case Option is
          when Red =>
             -- components for red
             Flashing : Boolean := True;
          when Yellow =>
             -- components for yellow
             Timeout    : Duration := 0.0;
          when Green =>
             -- components for green
             Whatever : Positive := 1;
       end case;
    end record;
...
Mutable_Traffic_Light   : Mutable_Variant_Record;                    -- not declaring a discriminant makes this record mutable
                                                                     -- it has the default discriminant/variant
                                                                     -- structure and values

Immutable_Traffic_Light : Mutable_Variant_Record (Option => Yellow); -- this record is immutable, the discriminant cannot be changed
                                                                     -- even though the type declaration allows for mutable objects
                                                                     -- with different discriminant values
...
Mutable_Traffic_Light   := (Option => Yellow,                        -- mutation requires assignment of all components
                            Location => 54,                          -- for the given variant structure
                            Timeout => 2.3);
...
-- restrictions on objects, causing them to be immutable
type Traffic_Light_Access is access Mutable_Variant_Record;
Any_Traffic_Light       : Traffic_Light_Access :=
                           new Mutable_Variant_Record;
Aliased_Traffic_Light   : aliased Mutable_Variant_Record;


Conversely, you can declare record types so that the discriminant along with the structure of the variant record may not be changed. To make a record type declaration immutable, the discriminant must not have a default value.

 type Traffic_Light is (Red, Yellow, Green);

 type Immutable_Variant_Record (Option : Traffic_Light) is -- no default value makes the record type immutable
    record
       -- common components
       Location : Natural := 0;
       case Option is
          when Red =>
             -- components for red
             Flashing : Boolean := True;
          when Yellow =>
             -- components for yellow
             Timeout    : Duration;
          when Green =>
             -- components for green
             Whatever : Positive := 1;
       end case;
    end record;
...
Default_Traffic_Light   : Immutable_Variant_Record;                    -- ILLEGAL!
Immutable_Traffic_Light : Immutable_Variant_Record (Option => Yellow); -- this record is immutable, since the type declaration is immutable

Union

edit

This language feature is only available from Ada 2005 on.

 type Traffic_Light is (Red, Yellow, Green);

 type Union (Option : Traffic_Light := Traffic_Light'First) is 
    record
       -- common components
       
       case Option is
          when Red =>
             -- components for red
          when Yellow =>
             -- components for yellow
          when Green =>
             -- components for green
       end case;
    end record;

 pragma Unchecked_Union (Union);
 pragma Convention (C, Union);    -- optional

The difference to a variant record is such that Option is not actually stored inside the record and never checked for correctness - it's just a dummy.

This kind of record is usually used for interfacing with C but can be used for other purposes as well (then without pragma Convention (C, Union);).

Tagged record

edit

The tagged record is one part of what in other languages is called a class. It is the basic foundation of object orientated programming in Ada. The other two parts a class in Ada needs is a package and primitive operations.

type Person is tagged 
   record
      Name   : String (1 .. 10);
      Gender : Gender_Type;
   end record;
type Programmer is new Person with
   record
      Skilled_In : Language_List;
   end record;

Ada 2005 only:

type Programmer is new Person 
                   and Printable 
with 
   record
      Skilled_In : Language_List;
   end record;

Abstract tagged record

edit

An abstract type has at least one abstract primitive operation, i.e. one of its operations is not defined and implementation must be provided by derivatives of the abstract type.

With aliased elements

edit

If you come from C/C++, you are probably used to the fact that every element of a record - which is not part of a bitset - has an address. In Ada, this is not true because records, just like arrays, can be packed. And just like arrays you can use aliased to ensure that an element can be accessed via an access type.

type Basic_Record is 
   record
      A : aliased Integer;
   end record ;

Please note: each element needs its own aliased.

Limited Records

edit

In addition to being variant, tagged, and abstract, records may also be limited (no assignment, and no predefined equality operation for Limited Types). In object oriented programming, when tagged objects are handled by references instead of copying them, this blends well with making objects limited.

See also

edit

Wikibook

edit

Ada Reference Manual

edit

Ada 95

edit

Ada 2005

edit

Ada Issues

edit