iTranslated by AI
Unique Syntax Features: Ada
This article is for day 25 of the Programming Language Unique Syntax Advent Calendar 2025.
I will introduce them with some of my personal preferences.
Sample code for binary search
Implemented intentionally using language features.
-- binary_search.ads (Specification)
package Binary_Search_Pkg is
type Index_Type is range 1 .. 1000;
type Result_Type is range -1 .. 1000; -- -1 means not found
type Int_Array is array (Index_Type range <>) of Integer;
function Binary_Search (Arr : Int_Array; Target : Integer) return Result_Type
with Pre => Arr'Length > 0,
Post => Binary_Search'Result = -1 or else
Arr(Index_Type(Binary_Search'Result)) = Target;
end Binary_Search_Pkg;
-- binary_search.adb (Body)
package body Binary_Search_Pkg is
function Binary_Search (Arr : Int_Array; Target : Integer) return Result_Type is
Left : Index_Type := Arr'First;
Right : Index_Type := Arr'Last;
Mid : Index_Type;
begin
while Left <= Right loop
Mid := (Left + Right) / 2;
if Arr(Mid) = Target then
return Result_Type(Mid);
elsif Arr(Mid) < Target then
Left := Mid + 1;
else
exit when Mid = Index_Type'First;
Right := Mid - 1;
end if;
end loop;
return -1;
end Binary_Search;
end Binary_Search_Pkg;
A language used in fields requiring high reliability, such as aerospace, defense, and railways.
Featured Syntax
Range Types
You can define the range of values a variable can take as a type.
-- Custom range types
type Percentage is range 0 .. 100;
type Month is range 1 .. 12;
type Temperature is range -40 .. 50;
-- Range check during usage
P : Percentage := 50; -- OK
P := 101; -- Runtime error!
-- Derived types
type Age is new Integer range 0 .. 150;
type Score is new Float range 0.0 .. 100.0;
Checks are performed at compile-time and run-time. This is effective for early bug detection.
Fixed-Point and Modular Types
Types for situations where you want to avoid floating-point errors or for bitwise operations.
-- Fixed-point types (for embedded/financial use)
type Voltage is delta 0.001 range 0.0 .. 5.0; -- 0.001 increment
type Money is delta 0.01 digits 10; -- 2 decimal places, 10-digit precision
-- Modular types (wrap around on overflow)
type Byte is mod 256; -- 0..255, returns to 0 at 256
type Word is mod 2**16;
You can even specify the step (increment).
Attributes
You can retrieve meta-information for types and variables using the ' syntax.
-- Array attributes
Arr'First -- First index
Arr'Last -- Last index
Arr'Length -- Length
Arr'Range -- Index range
-- Type attributes
Integer'First -- Minimum value
Integer'Last -- Maximum value
Integer'Image(X) -- String conversion
Integer'Value(S) -- Conversion from string
-- Enumeration attributes
type Day is (Mon, Tue, Wed, Thu, Fri, Sat, Sun);
Day'First -- Mon
Day'Succ(Mon) -- Tue (Next value)
Day'Pred(Wed) -- Tue (Previous value)
Day'Pos(Wed) -- 2 (Position)
It provides reflection-like features using the ' notation. 'Image and 'Range are particularly common.
Packages
The specification and the body are defined separately.
-- math_utils.ads (Specification)
package Math_Utils is
function Add (A, B : Integer) return Integer;
function Multiply (A, B : Integer) return Integer;
private
-- Private section
Secret_Value : constant := 42;
end Math_Utils;
-- math_utils.adb (Body)
package body Math_Utils is
function Add (A, B : Integer) return Integer is
begin
return A + B;
end Add;
function Multiply (A, B : Integer) return Integer is
begin
return A * B;
end Multiply;
end Math_Utils;
It resembles the separation of header files and implementation files but is more strictly enforced.
Tasks
Concurrency is built into the language as a feature. You can perform two-way data exchange through a "rendezvous" (synchronization).
task Calculator is
entry Compute(X : in Integer; Result : out Integer);
end Calculator;
task body Calculator is
begin
accept Compute(X : in Integer; Result : out Integer) do
Result := X * 2; -- Process and return during the rendezvous
end Compute;
end Calculator;
declare
Answer : Integer;
begin
Calculator.Compute(X => 21, Result => Answer);
Put_Line(Integer'Image(Answer)); -- 42
end;
It is unique in that you can define tasks that run independently and synchronize with each other.
The concurrency model is distinct, differing from the Generator + Promise pattern.
Contract-Based Programming (Ada 2012+)
Preconditions and postconditions can be described declaratively.
function Divide (A, B : Integer) return Integer
with Pre => B /= 0, -- Precondition
Post => Divide'Result * B <= A; -- Postcondition
type Stack is private
with Type_Invariant => Size (Stack) <= Max_Size; -- Invariant condition
procedure Push (S : in out Stack; Value : Integer)
with Pre => not Is_Full (S),
Post => Size (S) = Size (S'Old) + 1;
While it may seem surprising that side effects are permitted despite the focus on safety, pure functions are often impractical for hardware control. Instead, contracts make side effects traceable.
Named End Tags
You can explicitly indicate the correspondence by repeating the name at the end of a block.
This is the recommended style.
package Math_Utils is
...
end Math_Utils; -- Repeat the name
function Calc return Integer is
begin
...
end Calc;
You can feel the commitment to safety.
Named Parameters
Arguments can be specified by name, allowing them to be called even if the order is changed.
procedure Greet (Name : String; Age : Integer; Greeting : String := "Hello") is
begin
Put_Line (Greeting & ", " & Name & "! Age:" & Integer'Image(Age));
end Greet;
-- How to call
Greet ("Alice", 30, "Hi"); -- Positional
Greet (Name => "Bob", Age => 25); -- Named
Greet (30, Name => "Carol"); -- Order changed, mixed usage OK
Discussion