Ada: Data Types
Ada's type system is the language's core safety mechanism. Every value has exactly one type, distinct types never mix implicitly, and you can give a type a range of valid values that the compiler and run time both enforce. This page covers scalar types, subtypes, ranges, and derived types.
The Type Family
All Ada types fall into three families. The diagram is worth memorizing — every construct you meet later is somewhere on it:
| Family | Predefined types | Typical use |
|---|---|---|
| Integer types | Integer, Natural, Positive | Counts, indices, loop variables |
| Real types | Float, Long_Float, fixed point | Measurements, physical quantities |
| Enumeration | Boolean, Character, user-defined | States, modes, named choices |
| Composite | String, arrays, record | Structured data |
| Access | typed references | Linked structures, dynamic objects |
Defining Your Own Types
The predefined Integer is an implementation-defined size — fine for counts, useless for domain safety. Ada's range creates a new type that accepts only valid values:
with Ada.Text_IO; use Ada.Text_IO;
procedure Type_Demo is
-- A new integer type: values outside 1..31 are invalid by definition
type Day_Of_Month is range 1 .. 31;
-- A subtype: a restricted view of an existing type (no new checks beyond the range)
subtype Work_Hours is Integer range 0 .. 40;
Day : Day_Of_Month := 15;
Hours : Work_Hours := 38;
Plain : Integer := 42;
begin
-- Day := 32; -- compile error: 32 is not in 1 .. 31
-- Hours := Day; -- compile error: distinct types never mix
Plain := Hours; -- OK: a subtype IS its base type
Put_Line ("day " & Day_Of_Month'Image (Day));
end Type_Demo;
The distinction between type and subtype is central:
type Day_Of_Month is range 1 .. 31;creates a new type — incompatible withIntegerand with every other type, even one with the same range. Passing a bareIntegerwhere aDay_Of_Monthis expected is a compile error.subtype Work_Hours is Integer range 0 .. 40;is stillInteger— fully interchangeable, but values are checked against 0..40 on assignment.
Rule of thumb: type for meaning, subtype for validation. A Meters type stops you from adding meters to seconds; a Percent subtype stops any integer above 100.
Derived Types
new derives a type from an existing one, inheriting its operations — the foundation for domain models that still reuse arithmetic:
procedure Derived_Demo is
type Meters is new Integer range 0 .. 10_000; -- inherits +, -, =
type Seconds is new Integer range 0 .. 3_600; -- same base, different type
Distance : Meters := 500;
Elapsed : Seconds := 30;
begin
-- Distance := Distance + Elapsed; -- compile error: meters and seconds
-- ...deliberately refuse to mix. The fix is an explicit conversion:
Distance := Distance + Meters (Elapsed); -- legal, but you wrote the intent
null;
end Derived_Demo;
Explicit conversion (Meters (Elapsed)) is the only bridge between incompatible types — the compiler checks the value against the target range, and a violation raises Constraint_Error rather than silently truncating.
Attributes
Attributes are properties queried with a tick: they replace almost every "how big is X" question that C answers with headers or guesswork:
with Ada.Text_IO; use Ada.Text_IO;
procedure Attribute_Demo is
type Pressure is range 0 .. 4000;
P : Pressure := Pressure'First; -- the smallest valid value
begin
Put_Line ("first : " & Pressure'Image (P));
Put_Line ("last : " & Pressure'Image (Pressure'Last));
Put_Line ("size : " & Integer'Image (Pressure'Size) & " bits");
Put_Line ("image : " & Boolean'Image (P = 0)); -- TRUE
end Attribute_Demo;
'First, 'Last, 'Range, 'Length, 'Image, and 'Value are the six you will use daily. 'Value parses text back into the type — and raises Constraint_Error on garbage instead of returning nonsense.
Checked at Run Time Too
Range checks do not stop at compile time. A computed value that leaves the range raises Constraint_Error at the point of the bad assignment:
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Exceptions; use Ada.Exceptions;
procedure Overflow_Demo is
subtype Percent is Integer range 0 .. 100;
begin
begin
declare
P : Percent := 90;
begin
P := P + 20; -- 110 — out of range: raised HERE, at the assignment
Put_Line ("never printed");
end;
exception
when E : Constraint_Error =>
Put_Line ("caught: " & Exception_Message (E));
end;
end Overflow_Demo;
In C this code silently wraps or, worse, is undefined. In Ada the failure is a named, catchable event at the exact line of the error. Next: Expressions.