Ada: Records

A record groups named fields of different types under one name — the "struct" of the C family, but with variants, discriminants, and default values. Records are the foundation of all data modeling in Ada, and every later lesson (OOP especially) builds on them.

Basic Records

with Ada.Text_IO; use Ada.Text_IO;

procedure Record_Demo is
   type Point is record
      X, Y : Float := 0.0;         -- a default applies to every new object
   end record;

   type Player is record
      Name  : String (1 .. 20);
      Score : Natural;
      Pos   : Point;               -- nested record — records compose freely
   end record;

   P : Player := (Name => "alice              ", Score => 10, Pos => (others => <>));
begin
   P.Score := P.Score + 5;               -- dot notation, nested naturally
   P.Pos.X := 1.5;
   Put_Line (Natural'Image (P.Score));   -- 15
end Record_Demo;

Records assign as whole values: Q := P; copies every field. Equality (=, /=) compares every field. Records are never compared through their bytes, so padding garbage cannot create false inequality.

Variant Records and Discriminants

Ada's variant record is a checked union: a discriminant records which variant is active, and the compiler rejects access to fields of the wrong variant. The diagram shows how one type holds several layouts safely:

Variant record with a discriminant selecting between Circle and Rectangle layouts
Fig. 1 — The discriminant chooses the variant; fields of other variants are compile errors, not memory bugs.
procedure Variant_Demo is
   type Shape_Kind is (Circle, Rectangle);

   type Shape (Kind : Shape_Kind := Circle) is record
      X, Y : Float;
      case Kind is
         when Circle =>
            Radius : Float;
         when Rectangle =>
            Width, Height : Float;
      end case;
   end record;

   C : Shape;                       -- Kind defaults to Circle
   R : Shape (Kind => Rectangle);   -- fixed variant, Rectangle fields legal
begin
   C.Radius := 2.0;                 -- OK: C's variant is Circle
   --  R.Radius := 2.0;             -- compile error: R is a Rectangle
   null;
end Variant_Demo;

The variant record replaces a C union + tag enum pair with one construct where the pairing of tag and data is enforced by the type system — the "tagged union" done right.

Defaults and Initialization

Field defaults apply to every declaration; aggregates override selectively. Use others => <> to say "leave the rest at their defaults":

procedure Defaults_Demo is
   type Config is record
      Retries : Natural := 3;
      Timeout : Float   := 1.5;
      Verbose : Boolean := False;
   end record;

   Fast : Config := (Timeout => 0.2, others => <>);   -- override one, keep rest
begin
   null;   -- Fast.Retries = 3, Fast.Timeout = 0.2, Fast.Verbose = False
end Defaults_Demo;

Representation Clauses

For device drivers and binary formats, specify the exact layout with representation clauses — the record becomes a typed window onto hardware:

procedure Hardware_Demo is
   type Register is record
      Enable : Boolean;
      Mode   : Natural range 0 .. 3;
      Unused : Natural range 0 .. 2 ** 6 - 1;
   end record;
   for Register use record          -- byte layout, bit by bit
      Enable at 0 range 0 .. 0;
      Mode   at 0 range 1 .. 2;
      Unused at 0 range 3 .. 8;
   end record;
begin
   null;   -- reading/writing a Register object now maps the hardware byte
end Hardware_Demo;

Next: Access Types — how Ada handles references safely.