iTranslated by AI

The content below is an AI-generated translation. This is an experimental feature, and may contain errors. View original article
🔡

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.

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
GitHubで編集を提案

Discussion