TABELLA COMPARATIVA DELLE VERSIONI

Ada è un linguaggio progettato dal DoD statunitense per sistemi safety-critical e real-time. Ogni revisione espande le capacità mantenendo la retrocompatibilità e la verificabilità formale.

VersioneAnnoStandardNovità Principali
Ada 83 1983 MIL-STD-1815 / ISO 8652:1987 L'originale. Strong typing, packages, tasking nativo, generics, exception handling, representation clauses. Progettato per embedded DoD.
Ada 95 1995 ISO/IEC 8652:1995 OOP: tagged types, ereditarietà, polimorfismo con dispatching dinamico. Protected objects. Child packages. Annexes specializzati (Real-Time, Distributed, Systems Programming, Safety & Security).
Ada 2005 2007 ISO/IEC 8652:1995/Amd 1:2007 Interfacce (multiple inheritance of interfaces). Prefixed notation Obj.Method. Ada.Containers (Vectors, Maps, Sets). Access su subprograms migliorato. Limited aggregates. Nested generics semplificati.
Ada 2012 2012 ISO/IEC 8652:2012 Design by Contract: Pre, Post, Type_Invariant come aspect. Expression functions. Conditional/quantified expressions (if/case expressions, for all/for some). Flexible containers migliorati. Aspect specifications unificate.
Ada 2022 2023 ISO/IEC 8652:2023 Parallel blocks/loops. Iteratori generalizzati e procedural iterators. Light-weight user-defined literals. Delta aggregates. Target name @. 'Reduce attribute. Dichiarazione variabili in-place. Contratti rafforzati. Miglioramenti containers.
Nota: Ada prende il nome da Ada Lovelace, considerata la prima programmatrice della storia. Ogni revisione mantiene la retrocompatibilità: codice Ada 83 valido compila con un compilatore Ada 2022.
STRUTTURA BASE

Ogni programma Ada ha un sottoprogramma principale (procedura senza package obbligatorio). Il linguaggio è case-insensitive. I statement terminano con ;.

HELLO WORLD
with Ada.Text_IO;  -- importa il package di I/O testuale

procedure Hello is
begin
   Ada.Text_IO.Put_Line ("Hello, Ada World!");
end Hello;
STRUTTURA CON USE CLAUSE
with Ada.Text_IO;  use Ada.Text_IO;   -- rende visibili i nomi direttamente
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;

procedure Main is
   X : Integer := 42;
begin
   Put ("Valore: ");
   Put (X, Width => 0);   -- stampa senza padding
   New_Line;
end Main;
COMMENTI
-- Questo è un commento (unico stile: doppio trattino fino a fine riga)
-- Ada NON ha commenti multi-riga: si usano più righe con --
with importa un package (simile a #include in C). use rende i nomi visibili senza qualifica (opzionale, preferire la qualifica per chiarezza).
TIPI SCALARI

Ada ha un sistema di tipi fortemente tipizzato: non esistono conversioni implicite tra tipi diversi.

TipoDescrizioneEsempio
Integer Intero con segno (almeno 16 bit, tipicamente 32) X : Integer := -42;
Natural Subtype di Integer: 0 .. Integer'Last N : Natural := 0;
Positive Subtype di Integer: 1 .. Integer'Last P : Positive := 1;
Float Virgola mobile (almeno 6 cifre significative) F : Float := 3.14;
Long_Float Virgola mobile a doppia precisione D : Long_Float := 3.14159_26535;
Character Singolo carattere (Latin-1) C : Character := 'A';
Wide_Character Carattere Unicode BMP W : Wide_Character := 'Ω';
Boolean True / False B : Boolean := True;
String Array di Character a lunghezza fissa S : String (1..5) := "Hello";
Duration Tipo fixed-point per intervalli di tempo D : Duration := 1.5;
TIPI NUMERICI DEFINITI DALL'UTENTE
-- Tipo intero con range esplicito (il compilatore sceglie la rappresentazione)
type Day_Number is range 1 .. 31;

-- Tipo floating-point con precisione minima (cifre significative)
type Velocity is digits 8;               -- almeno 8 cifre
type Probability is digits 6 range 0.0 .. 1.0;

-- Tipo fixed-point (aritmetica esatta, usato in sistemi finanziari/embedded)
type Voltage is delta 0.001 range 0.0 .. 5.0;       -- ordinary fixed
type Money   is delta 0.01 digits 12;                 -- decimal fixed

-- Tipo modular (aritmetica unsigned con wrapping)
type Byte  is mod 256;          -- 0..255, overflow fa wrap
type Word  is mod 2**16;       -- 0..65535
Safety: I range vengono verificati a runtime. Assegnare 32 a un Day_Number solleva Constraint_Error. Questo previene intere classi di bug tipiche di C/C++.
VARIABILI E COSTANTI
procedure Vars_Demo is
   -- Variabili (dichiarate nella parte dichiarativa, prima di begin)
   Count   : Integer := 0;              -- inizializzata
   Name    : String (1..10);            -- non inizializzata (attenzione!)
   Active  : Boolean := False;

   -- Costanti (valore immutabile)
   Pi      : constant Float   := 3.14159_26535;
   Max_Len : constant Integer := 1024;

   -- Costante con tipo dedotto dal contesto (named number)
   Factor  : constant := 2 * 3;        -- universal_integer, nessun tipo specifico

   -- Rinomina (alias, zero-cost)
   C : Integer renames Count;
begin
   C := C + 1;  -- modifica Count tramite alias
end Vars_Demo;
Separatore numerico: L'underscore _ è ammesso nei letterali numerici per leggibilità: 1_000_000, 3.14_159, 16#FF_FF#.
BASI NUMERICHE
-- Letterali in base diversa: base#valore#
Hex  : Integer := 16#FF#;      -- 255 in esadecimale
Oct  : Integer := 8#77#;       -- 63 in ottale
Bin  : Integer := 2#1010_0011#; -- 163 in binario
OPERATORI
ARITMETICI
OpSignificato
+ -Somma, sottrazione
* /Moltiplicazione, divisione
modModulo (segno del divisore)
remResto (segno del dividendo)
**Elevamento a potenza
absValore assoluto
RELAZIONALI / LOGICI
OpSignificato
= /=Uguale, diverso
< > <= >=Confronto
and or xorLogici (booleani e bit-a-bit)
notNegazione logica
and thenShort-circuit AND
or elseShort-circuit OR
&Concatenazione stringhe
Attenzione: and/or valutano ENTRAMBI gli operandi. Usare and then/or else per la valutazione cortocircuitata (essenziale per guardie null-check).
INPUT / OUTPUT
with Ada.Text_IO;          use Ada.Text_IO;
with Ada.Integer_Text_IO;  use Ada.Integer_Text_IO;
with Ada.Float_Text_IO;    use Ada.Float_Text_IO;

procedure IO_Demo is
   N    : Integer;
   Line : String (1..80);
   Last : Natural;
begin
   -- Output
   Put ("Testo senza a-capo");
   Put_Line ("Testo con a-capo");
   New_Line;                          -- riga vuota
   Put (N, Width => 5);              -- intero con padding
   Put (3.14, Fore => 1, Aft => 2, Exp => 0);  -- "3.14"

   -- Input
   Get (N);                           -- legge un intero
   Skip_Line;                         -- consuma il newline residuo
   Get_Line (Line, Last);             -- legge una riga, Last = ultimo carattere usato
   Put_Line (Line (1..Last));         -- stampa solo la parte letta
end IO_Demo;
PACKAGE I/O PRINCIPALI
PackageUso
Ada.Text_IOStringhe e caratteri
Ada.Integer_Text_IOInteger standard
Ada.Float_Text_IOFloat standard
Ada.Text_IO.Unbounded_IOUnbounded_String I/O
Ada.Sequential_IOFile binari sequenziali
Ada.Direct_IOFile binari ad accesso diretto
Ada.Streams.Stream_IOI/O basato su stream
FILE I/O — TESTUALE E BINARIO
FILE TESTUALE — SCRITTURA
with Ada.Text_IO; use Ada.Text_IO;

procedure Write_File is
   F : File_Type;
begin
   Create (F, Out_File, "output.txt");
   Put_Line (F, "Prima riga");
   Put_Line (F, "Seconda riga");
   Close (F);
end Write_File;
FILE TESTUALE — LETTURA
with Ada.Text_IO; use Ada.Text_IO;

procedure Read_File is
   F    : File_Type;
   Line : String (1..256);
   Last : Natural;
begin
   Open (F, In_File, "input.txt");
   while not End_Of_File (F) loop
      Get_Line (F, Line, Last);
      Put_Line (Line (1..Last));
   end loop;
   Close (F);
end Read_File;
APPEND A FILE ESISTENTE
Open (F, Append_File, "log.txt");   -- apre in modalità append
Put_Line (F, "Nuova riga in coda");
Close (F);
MODI DI APERTURA (File_Mode)
ModoDescrizione
In_FileSolo lettura
Out_FileSolo scrittura (sovrascrive)
Append_FileScrittura in coda
FILE BINARIO — SEQUENTIAL_IO
with Ada.Sequential_IO;

procedure Bin_Sequential is
   package Int_IO is new Ada.Sequential_IO (Integer);
   use Int_IO;
   F : Int_IO.File_Type;
   V : Integer;
begin
   -- Scrittura
   Create (F, Out_File, "data.bin");
   Write (F, 42);
   Write (F, 99);
   Close (F);

   -- Lettura
   Open (F, In_File, "data.bin");
   while not End_Of_File (F) loop
      Read (F, V);    -- legge un Integer alla volta
   end loop;
   Close (F);
end Bin_Sequential;
FILE BINARIO — DIRECT_IO (ACCESSO DIRETTO)
with Ada.Direct_IO;

procedure Bin_Direct is
   type Sensor is record
      Id    : Integer;
      Value : Float;
   end record;

   package Sensor_IO is new Ada.Direct_IO (Sensor);
   use Sensor_IO;
   F : Sensor_IO.File_Type;
   S : Sensor;
begin
   Create (F, Inout_File, "sensors.bin");
   Write (F, (Id => 1, Value => 23.5));
   Write (F, (Id => 2, Value => 18.0));

   -- Lettura per posizione (indice parte da 1)
   Read (F, S, 2);   -- legge il secondo record
   Set_Index (F, 1); -- riposiziona all'inizio
   Close (F);
end Bin_Direct;
Gestione errori: Usare Is_Open (F) per verificare se il file è aperto. Le operazioni su file possono sollevare Name_Error (file non trovato), Status_Error (file già aperto/chiuso) e Use_Error (operazione non valida per il modo).
IF / ELSIF / ELSE
if Temp > 100.0 then
   Put_Line ("Ebollizione");
elsif Temp > 0.0 then
   Put_Line ("Liquido");
else
   Put_Line ("Ghiaccio");
end if;
IF EXPRESSION (Ada 2012+)
-- Espressione condizionale (simile al ternario di C)
Status : String := (if Active then "ON " else "OFF");
CASE STATEMENT
case Day is
   when Mon          => Put_Line ("Lunedì");
   when Tue .. Thu   => Put_Line ("Infrasettimanale");
   when Fri          => Put_Line ("Venerdì!");
   when Sat | Sun    => Put_Line ("Weekend");
end case;
Safety: Il case deve coprire TUTTI i valori possibili del tipo. Il compilatore genera un errore se manca un valore. Usa when others => come default obbligatorio se non elenchi tutti i valori.
CASE EXPRESSION (Ada 2012+)
Msg : String := (case Level is
   when 0      => "Off",
   when 1..5  => "Low",
   when others => "High");
LOOP / WHILE / FOR
LOOP INFINITO
loop
   Do_Something;
   exit when Done;  -- uscita condizionale
end loop;
WHILE LOOP
while Count < 10 loop
   Count := Count + 1;
end loop;
FOR LOOP (CRESCENTE)
for I in 1 .. 10 loop
   Put (I, Width => 0);
end loop;
-- I non è visibile fuori dal loop
FOR LOOP (DECRESCENTE)
for I in reverse 1 .. 10 loop
   Put (I, Width => 0);
end loop;
FOR SU TIPI DISCRETI
type Color is (Red, Green, Blue);

for C in Color loop            -- itera su tutti i valori dell'enum
   Put_Line (Color'Image (C));   -- stampa "RED", "GREEN", "BLUE"
end loop;

for C in Color'Range loop      -- equivalente
   null;
end loop;
LOOP CON LABEL E EXIT
Outer :
for I in 1 .. 10 loop
   Inner :
   for J in 1 .. 10 loop
      exit Outer when I * J > 50;  -- esce dal loop esterno
   end loop Inner;
end loop Outer;
PARALLEL LOOP (Ada 2022)
parallel
for I in 1 .. 1000 loop
   Result (I) := Compute (Data (I));  -- iterazioni indipendenti eseguite in parallelo
end loop;
SUBTYPES — VINCOLI SENZA NUOVI TIPI

Un subtype restringe il range di un tipo esistente senza creare un tipo nuovo. Valori di un subtype e del tipo padre sono compatibili senza conversione.

subtype Small_Int  is Integer range -100 .. 100;
subtype Percentage is Integer range 0 .. 100;
subtype Upper_Char is Character range 'A' .. 'Z';

A : Small_Int  := 50;
B : Integer    := A;      -- OK: compatibili (stesso tipo base)
C : Percentage := A;      -- OK a compile-time, check a runtime (50 è nel range)
Perché sono fondamentali: I subtypes documentano le invarianti nel tipo stesso. Un parametro Percentage non può MAI contenere 101: il runtime lo garantisce con Constraint_Error. Questo elimina interi bug di validazione rispetto a un semplice int.
SUBTYPES PREDEFINITI
-- Già definiti nello standard:
subtype Natural  is Integer range 0 .. Integer'Last;
subtype Positive is Integer range 1 .. Integer'Last;
DERIVED TYPES — SICUREZZA PER INCOMPATIBILITÀ

Un derived type crea un tipo completamente nuovo. Valori del tipo derivato e del padre sono incompatibili: servono conversioni esplicite. Questo previene errori di confusione tra unità di misura.

type Meters  is new Float;
type Seconds is new Float;
type MPS     is new Float;     -- metri al secondo

function Speed (D : Meters; T : Seconds) return MPS is
begin
   return MPS (Float (D) / Float (T));  -- conversioni esplicite obbligatorie
end Speed;

Distance : Meters  := 100.0;
Time     : Seconds := 9.58;
V        : MPS     := Speed (Distance, Time);  -- OK
-- V := Distance;  -- ERRORE di compilazione! Meters /= MPS
Il caso Mars Climate Orbiter (1999): La sonda si schiantò perché un componente software usava libbre-forza·secondo e un altro newton·secondo. In Ada, type Pounds is new Float; e type Newtons is new Float; avrebbero reso questa confusione un errore di compilazione.
DERIVED CON RANGE
type Temperature_C is new Float range -273.15 .. 1_000_000.0;
type Temperature_K is new Float range 0.0 .. 1_000_000.0;
-- Non puoi assegnare Celsius a Kelvin senza convertire esplicitamente
ENUMERAZIONI
type Direction is (North, South, East, West);
type Weekday   is (Mon, Tue, Wed, Thu, Fri, Sat, Sun);
subtype Work_Day is Weekday range Mon .. Fri;

Dir : Direction := North;
Dir := Direction'Succ (Dir);        -- South (successore)
Dir := Direction'Pred (Dir);        -- North (predecessore)
Put_Line (Direction'Image (Dir));   -- "NORTH" (stringa)
Dir := Direction'Value ("EAST");   -- parsing da stringa
N   := Direction'Pos (East);        -- 2 (posizione ordinale)
Dir := Direction'Val (3);           -- West (valore da posizione)
Attributi utili: 'First, 'Last, 'Range, 'Succ, 'Pred, 'Pos, 'Val, 'Image, 'Value. Funzionano su tutti i tipi discreti.
ARRAY
-- Array a indice fisso (constrained)
type Vector is array (1 .. 3) of Float;
V : Vector := (1.0, 2.0, 3.0);

-- Array a indice variabile (unconstrained)
type Int_Array is array (Integer range <>) of Integer;
Data : Int_Array (1 .. 100) := (others => 0);  -- inizializza tutto a 0

-- Array indicizzato da enumerazione
type Score_Table is array (Weekday) of Natural;
Scores : Score_Table := (Mon => 10, Fri => 20, others => 0);

-- Array multidimensionale
type Matrix is array (Positive range <>, Positive range <>) of Float;
M : Matrix (1..3, 1..3) := (others => (others => 0.0));

-- Slicing
Sub : Int_Array := Data (5 .. 10);   -- slice: copia elementi 5..10
Attributi array: A'First, A'Last, A'Range, A'Length. Usali sempre nei loop: for I in A'Range loop — previene off-by-one.
RECORD
type Point is record
   X : Float := 0.0;    -- valore di default
   Y : Float := 0.0;
end record;

P1 : Point;                               -- (0.0, 0.0) per default
P2 : Point := (X => 3.0, Y => 4.0);    -- aggregate con nomi
P3 : Point := (1.0, 2.0);               -- aggregate posizionale

P1.X := 5.0;   -- accesso ai campi con notazione punto
RECORD CON DISCRIMINANTE (VARIANT RECORD)
type Shape_Kind is (Circle, Rectangle);

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

S1 : Shape := (Kind => Circle,    Radius => 5.0);
S2 : Shape := (Kind => Rectangle, Width => 3.0, Height => 4.0);
-- S1.Width sarebbe Constraint_Error: il discriminante è Circle
ACCESS TYPES (PUNTATORI)

Ada chiama i puntatori access types. Sono fortemente tipizzati e di default inizializzati a null.

type Int_Ptr is access Integer;

P : Int_Ptr;                      -- automaticamente null
P := new Integer'(42);           -- allocazione su heap
Put (P.all, Width => 0);         -- dereference con .all → stampa 42
P.all := 99;                     -- modifica il valore puntato

-- Access a subprogram (function pointer)
type Math_Func is access function (X : Float) return Float;
DEALLOCAZIONE ESPLICITA
with Ada.Unchecked_Deallocation;

procedure Free is new Ada.Unchecked_Deallocation
   (Object => Integer, Name => Int_Ptr);
-- Dopo: Free (P);  →  P diventa null
Safety: Ada non ha aritmetica dei puntatori. L'accesso a null solleva Constraint_Error. Usare not null access per forzare la non-nullità a livello di tipo.
PACKAGE — SPECIFICA E BODY

Il package è l'unità fondamentale di modularità in Ada. La specifica (.ads) dichiara l'interfaccia pubblica. Il body (.adb) contiene l'implementazione.

SPECIFICA (stack.ads)
package Stack is
   Max : constant := 100;

   procedure Push (Val : in Integer);
   function  Pop return Integer;
   function  Is_Empty return Boolean;

   Stack_Overflow  : exception;
   Stack_Underflow : exception;
end Stack;
BODY (stack.adb)
package body Stack is
   Data : array (1..Max) of Integer;
   Top  : Natural := 0;

   procedure Push (Val : in Integer) is
   begin
      if Top = Max then
         raise Stack_Overflow;
      end if;
      Top := Top + 1;
      Data (Top) := Val;
   end Push;

   function Pop return Integer is
      Val : Integer;
   begin
      if Top = 0 then
         raise Stack_Underflow;
      end if;
      Val := Data (Top);
      Top := Top - 1;
      return Val;
   end Pop;

   function Is_Empty return Boolean is
      (Top = 0);
end Stack;
Convenzione file GNAT: package_name.ads (specifica), package_name.adb (body). Un file per unità di compilazione. Il compilatore impone la corrispondenza nomi.
VISIBILITÀ — PRIVATE / LIMITED
package Sensor is
   -- Parte PUBBLICA: visibile ai client
   type Reading is private;             -- tipo opaco
   type Handle  is limited private;     -- opaco + no copia/confronto

   function Get_Value (R : Reading) return Float;
   function Create (Id : Positive) return Handle;

private
   -- Parte PRIVATA: completamento del tipo, non visibile ai client
   type Reading is record
      Value     : Float := 0.0;
      Timestamp : Duration := 0.0;
   end record;

   type Handle is record
      Sensor_Id : Positive;
      FD        : Integer := -1;
   end record;
end Sensor;
DichiarazioneAssegnamento=, /=Campi visibili
is privateSì (:=)No (solo nel body)
is limited privateNoNoNo (solo nel body)
Child packages (Ada 95+) possono accedere alla parte private del genitore: package Sensor.Calibration is ... vede i campi interni di Sensor.
GENERICS

I generics Ada sono simili ai template C++ ma con controllo formale: il contratto del parametro generico è verificato al punto di definizione, non solo all'istanziazione.

-- Procedura generica: scambia due valori di qualsiasi tipo
generic
   type Element is private;   -- qualsiasi tipo con := e =
procedure Generic_Swap (A, B : in out Element);

procedure Generic_Swap (A, B : in out Element) is
   Tmp : Element := A;
begin
   A := B;
   B := Tmp;
end Generic_Swap;

-- Istanziazione esplicita (nessuna deduzione implicita come in C++)
procedure Swap_Int   is new Generic_Swap (Integer);
procedure Swap_Float is new Generic_Swap (Float);
PACKAGE GENERICO (STACK GENERICO)
generic
   type Item is private;
   Size : Positive;
package Generic_Stack is
   procedure Push (Val : Item);
   function  Pop return Item;
end Generic_Stack;

-- Istanziazione
package Int_Stack  is new Generic_Stack (Item => Integer, Size => 50);
package Char_Stack is new Generic_Stack (Character, 256);
PARAMETRI FORMALI GENERICI
Parametro FormaleSignificato
type T is privateQualsiasi tipo con := e =
type T is limited privateQualsiasi tipo (anche senza := e =)
type T is (<>)Tipo discreto (intero o enum)
type T is range <>Tipo intero con segno
type T is mod <>Tipo modular
type T is digits <>Tipo floating-point
type T is delta <>Tipo fixed-point
type T is tagged privateTipo tagged (per OOP)
with function F (...) return TParametro funzione
with package P is new G (<>)Parametro package istanziato
PROCEDURE E FUNCTION
-- Procedura (nessun valore di ritorno)
procedure Greet (Name : in String) is
begin
   Put_Line ("Hello, " & Name & "!");
end Greet;

-- Funzione (deve sempre ritornare un valore)
function Max (A, B : Integer) return Integer is
   (if A > B then A else B);   -- expression function (Ada 2012)
MODALITÀ DEI PARAMETRI
ModoLetturaScritturaUso tipico
in (default)NoInput sola lettura
outSì*Output (valore di ritorno multiplo)
in outModifica in-place

*In Ada 2012+ i parametri out sono leggibili fin dall'inizio del sottoprogramma (hanno il valore di default del tipo o il valore passato). In Ada 95/2005 la lettura prima della prima assegnazione è erronea.

PARAMETRI NAMED E DEFAULT
procedure Log
   (Message : String;
    Level   : Natural := 0;       -- valore di default
    To_File : Boolean := False) is ...

-- Chiamate equivalenti:
Log ("test");
Log ("test", Level => 2);
Log (Message => "err", To_File => True, Level => 3);
OVERLOADING

Ada supporta overloading per nome, tipo dei parametri e tipo di ritorno (unico tra i linguaggi mainstream).

function Convert (X : Integer) return Float  is (Float (X));
function Convert (X : Float)   return Integer is (Integer (X));
function Convert (X : Integer) return String  is (Integer'Image (X));

-- Overloading di operatori
function "+" (A, B : Vector) return Vector is
   ((A(1)+B(1), A(2)+B(2), A(3)+B(3)));
TAGGED TYPES — OOP IN ADA

Ada 95+ implementa l'OOP tramite tagged types: record con tag implicito che identifica il tipo a runtime (simile alla vtable del C++).

package Shapes is
   type Shape is tagged record
      X, Y : Float := 0.0;    -- posizione
   end record;

   function Area (S : Shape) return Float;          -- "metodo"
   procedure Move (S : in out Shape; DX, DY : Float);
end Shapes;

package body Shapes is
   function Area (S : Shape) return Float is (0.0);

   procedure Move (S : in out Shape; DX, DY : Float) is
   begin
      S.X := S.X + DX;
      S.Y := S.Y + DY;
   end Move;
end Shapes;
Notazione Ada 2005+: Si può scrivere S.Move (1.0, 2.0) invece di Move (S, 1.0, 2.0) — la prefixed notation rende il codice più leggibile in stile OOP.
EREDITARIETÀ
with Shapes; use Shapes;

package Circles is
   type Circle is new Shape with record    -- estende Shape
      Radius : Float := 1.0;
   end record;

   -- Override del metodo Area
   overriding                                -- keyword opzionale ma raccomandata (Ada 2005)
   function Area (S : Circle) return Float;

   -- Nuovo metodo (solo per Circle)
   function Circumference (S : Circle) return Float;
end Circles;

package body Circles is
   Pi : constant := 3.14159_26535;

   function Area (S : Circle) return Float is
      (Pi * S.Radius ** 2);

   function Circumference (S : Circle) return Float is
      (2.0 * Pi * S.Radius);
end Circles;
TIPO ASTRATTO
type Abstract_Shape is abstract tagged record
   X, Y : Float;
end record;

function Area (S : Abstract_Shape) return Float is abstract;
-- Non si possono creare istanze di Abstract_Shape
-- Le sottoclassi DEVONO implementare Area
POLIMORFISMO — CLASS-WIDE E DISPATCHING
with Shapes;  use Shapes;
with Circles; use Circles;

procedure Poly_Demo is

   -- Shape'Class = tutti i tipi derivati da Shape (class-wide type)
   procedure Print_Area (S : Shape'Class) is
   begin
      -- Dispatching dinamico: chiama la versione corretta di Area
      Put_Line ("Area = " & Float'Image (S.Area));
   end Print_Area;

   S : Shape  := (X => 0.0, Y => 0.0);
   C : Circle := (X => 1.0, Y => 2.0, Radius => 5.0);
begin
   Print_Area (S);   -- chiama Shape.Area   → 0.0
   Print_Area (C);   -- chiama Circle.Area  → 78.54
end Poly_Demo;
ACCESSO CLASS-WIDE (PUNTATORI POLIMORFICI)
type Shape_Access is access Shape'Class;  -- punta a qualsiasi Shape o derivato

Ptr : Shape_Access := new Circle'(X => 0.0, Y => 0.0, Radius => 3.0);
A   : Float := Ptr.Area;   -- dispatching dinamico tramite puntatore
Regola: In Ada il dispatch avviene solo su parametri di tipo T'Class. Un parametro di tipo specifico T produce una chiamata statica (risolta a compile-time).
INTERFACCE (Ada 2005+)
package Drawable is
   type Drawable_Interface is interface;   -- nessun campo, solo operazioni

   procedure Draw (Self : Drawable_Interface) is abstract;
end Drawable;

package Printable is
   type Printable_Interface is interface;

   function To_String (Self : Printable_Interface) return String is abstract;
end Printable;

-- Ereditarietà multipla di interfacce + ereditarietà singola di tipo
type Widget is new Shape
   and Drawable.Drawable_Interface
   and Printable.Printable_Interface
with record
   Label : String (1..20);
end record;

-- Widget deve implementare Draw, To_String e (opzionalmente override) Area
TASK — CONCORRENZA NATIVA

Ada ha il supporto alla concorrenza integrato nel linguaggio (non in libreria). I task sono thread leggeri gestiti dal runtime Ada.

TASK SEMPLICE (ANONIMO)
procedure Task_Demo is

   task Background;
   task body Background is
   begin
      for I in 1..5 loop
         Put_Line ("BG: " &
            Integer'Image (I));
         delay 1.0;
      end loop;
   end Background;

begin
   -- Background parte automaticamente
   Put_Line ("Main attivo");
   delay 3.0;
   Put_Line ("Main finito");
   -- attende la terminazione di
   -- Background prima di uscire
end Task_Demo;
TASK TYPE (RIUTILIZZABILE)
task type Worker (Id : Positive);

task body Worker is
begin
   Put_Line ("Worker" &
      Positive'Image (Id) &
      " avviato");
   delay 2.0;
   Put_Line ("Worker" &
      Positive'Image (Id) &
      " completato");
end Worker;

-- Crea 3 worker paralleli
W1 : Worker (1);
W2 : Worker (2);
W3 : Worker (3);
DELAY E DELAY UNTIL
delay 0.5;                        -- pausa di almeno 0.5 secondi

with Ada.Real_Time; use Ada.Real_Time;
Next : Time := Clock;
loop
   Do_Periodic_Work;
   Next := Next + Milliseconds (100);
   delay until Next;                -- timing deterministico (no drift)
end loop;
PARALLEL BLOCK (Ada 2022)
parallel do
   Part_A := Compute_A (Data);
and
   Part_B := Compute_B (Data);
and
   Part_C := Compute_C (Data);
end do;
-- Tutte le sezioni eseguite in parallelo, si sincronizzano alla fine
PROTECTED OBJECTS — ACCESSO CONCORRENTE SICURO

I protected objects forniscono mutua esclusione e sincronizzazione senza lock espliciti — il runtime garantisce le invarianti.

protected type Shared_Counter is
   procedure Increment;          -- accesso esclusivo (read-write)
   procedure Decrement;
   function  Value return Integer;  -- accesso concorrente (read-only)

   entry Wait_Until_Zero;        -- entry: blocca il chiamante finché la guardia è False
private
   Count : Integer := 0;
end Shared_Counter;

protected body Shared_Counter is
   procedure Increment is
   begin
      Count := Count + 1;
   end Increment;

   procedure Decrement is
   begin
      Count := Count - 1;
   end Decrement;

   function Value return Integer is (Count);

   entry Wait_Until_Zero when Count = 0 is  -- barrier/guardia
   begin
      null;  -- si sblocca quando Count = 0
   end Wait_Until_Zero;
end Shared_Counter;
ComponenteAccessoSemantica
functionMultipli lettori concorrentiRead-only, nessuna modifica allo stato
procedureUn solo writer alla voltaRead-write, mutua esclusione
entryCome procedure + guardia booleanaIl chiamante si blocca se la guardia è False
RENDEZVOUS E SELECT

Il rendezvous è il meccanismo di comunicazione sincrona tra task: il chiamante si blocca finché il task accettante non esegue l'accept.

task Server is
   entry Request (Data : in Integer; Result : out Integer);
   entry Shutdown;
end Server;

task body Server is
   Running : Boolean := True;
begin
   while Running loop
      select
         accept Request (Data : in Integer; Result : out Integer) do
            Result := Data * 2;     -- elaborazione sincrona
         end Request;
      or
         accept Shutdown;
         Running := False;
      or
         delay 5.0;                -- timeout: nessuna richiesta in 5s
         Put_Line ("Timeout");
      end select;
   end loop;
end Server;

-- Uso dal chiamante:
R : Integer;
Server.Request (21, R);   -- R = 42 dopo il rendezvous
Server.Shutdown;
DESIGN BY CONTRACT (Ada 2012+)

Ada 2012 introduce aspect specifications per precondizioni, postcondizioni e invarianti di tipo — verificabili a runtime e/o staticamente con SPARK.

function Divide (A, B : Float) return Float
   with Pre  => B /= 0.0,                -- precondizione: B non zero
        Post => Divide'Result * B = A;  -- postcondizione

function Sqrt (X : Float) return Float
   with Pre  => X >= 0.0,
        Post => Sqrt'Result >= 0.0
                 and then abs (Sqrt'Result ** 2 - X) < 1.0E-6;
TYPE INVARIANT
package Dates is
   type Date is private
      with Type_Invariant => Is_Valid (Date);   -- verificato dopo ogni modifica pubblica

   function Is_Valid (D : Date) return Boolean;
   function Create (Y, M, D : Positive) return Date;
private
   type Date is record
      Year  : Positive;
      Month : Positive range 1 .. 12;
      Day   : Positive range 1 .. 31;
   end record;
end Dates;
SUBTYPE PREDICATE (Ada 2012)
subtype Even is Integer
   with Dynamic_Predicate => Even mod 2 = 0;

subtype Prime is Positive
   with Dynamic_Predicate => Is_Prime (Prime);

subtype Weekday_Only is Weekday
   with Static_Predicate => Weekday_Only in Mon .. Fri;

X : Even := 4;   -- OK
-- X := 3;        -- Assertion_Error a runtime!
QUANTIFIED EXPRESSIONS
-- "per tutti gli elementi..." / "esiste un elemento..."
All_Positive : Boolean := (for all I in Data'Range => Data (I) > 0);
Has_Zero     : Boolean := (for some I in Data'Range => Data (I) = 0);
EXCEPTION HANDLING
with Ada.Text_IO;            use Ada.Text_IO;
with Ada.Exceptions;         use Ada.Exceptions;
with Ada.Integer_Text_IO;    use Ada.Integer_Text_IO;

procedure Exception_Demo is
   My_Error : exception;               -- dichiarazione eccezione custom
   N : Integer;
begin
   Put ("Inserisci un numero: ");
   Get (N);

   if N < 0 then
      raise My_Error with "Numero negativo non ammesso";
   end if;

   Put (N / (N - 5), Width => 0);     -- possibile divisione per zero

exception
   when E : My_Error =>
      Put_Line ("Errore custom: " & Exception_Message (E));

   when Constraint_Error =>
      Put_Line ("Errore: overflow, divisione per zero o range violato");

   when Data_Error =>
      Put_Line ("Input non valido");

   when E : others =>
      Put_Line ("Eccezione imprevista: " & Exception_Name (E));
      Put_Line (Exception_Information (E));
      raise;  -- ri-solleva l'eccezione
end Exception_Demo;
ECCEZIONI PREDEFINITE
EccezioneQuando viene sollevata
Constraint_ErrorRange violato, overflow, divisione per zero, accesso null, indice fuori bounds
Program_ErrorErrori strutturali: funzione senza return, elaborazione errata, access before elab.
Storage_ErrorMemoria esaurita (heap o stack overflow)
Tasking_ErrorErrori di comunicazione tra task (task abortito durante rendezvous)
Data_ErrorInput malformato durante I/O
PRAGMA E ASPECT

I pragma sono direttive al compilatore (stile Ada 83–2005). Gli aspect (Ada 2012+) sono la sintassi moderna e unificata per le stesse informazioni.

Pragma (vecchio stile)Aspect (Ada 2012+)Significato
pragma Inline (F);with InlineSuggerisce inlining
pragma Pure (Pkg);with PurePackage senza stato (idempotente)
pragma Preelaborate;with PreelaborateElaborazione prima dell'esecuzione
pragma Suppress (Range_Check);with Suppress => ...Disabilita check runtime (unsafe!)
pragma Convention (C, T);with Convention => CCalling convention C
pragma Import (C, F, "f");with Import, Convention => CImporta simbolo esterno
pragma Volatile (V);with VolatileAccesso memory-mapped
pragma Atomic (V);with AtomicAccesso atomico
pragma Pack (T);with PackCompatta la rappresentazione
with Pre => ...Precondizione (solo aspect)
with Post => ...Postcondizione (solo aspect)
with Type_Invariant => ...Invariante di tipo (solo aspect)
pragma Unreferenced (X);Sopprime warning variabile non usata
SPARK: Con pragma SPARK_Mode (On) si abilita l'analisi formale SPARK, che può dimostrare l'assenza di runtime errors senza eseguire il codice.
REPRESENTATION CLAUSES

Ada permette di controllare la rappresentazione in memoria a livello di bit, essenziale per protocolli hardware e registri embedded.

-- Dimensione esplicita di un tipo
type Status_Byte is mod 256;
for Status_Byte'Size use 8;     -- esattamente 8 bit

-- Enumerazione con valori di rappresentazione espliciti
type Command is (Reset, Start, Stop, Read_Data);
for Command use (Reset => 0, Start => 1, Stop => 2, Read_Data => 16#FF#);

-- Record layout a livello di bit (per registri hardware)
type Control_Register is record
   Enable     : Boolean;
   Mode       : Integer range 0..3;
   Reserved   : Integer range 0..0;
   Interrupt  : Boolean;
   Data_Ready : Boolean;
end record;

for Control_Register use record
   Enable     at 0 range 0 .. 0;   -- bit 0
   Mode       at 0 range 1 .. 2;   -- bit 1-2
   Reserved   at 0 range 3 .. 4;   -- bit 3-4
   Interrupt  at 0 range 5 .. 5;   -- bit 5
   Data_Ready at 0 range 6 .. 6;   -- bit 6
end record;
for Control_Register'Size use 8;

-- Indirizzo specifico (memory-mapped I/O)
Ctrl : Control_Register;
for Ctrl'Address use System.Storage_Elements.To_Address (16#4000_0000#);
pragma Volatile (Ctrl);
LOW-LEVEL & INTERFACCIA CON C
with Interfaces.C;       use Interfaces.C;
with Interfaces.C.Strings;

-- Importa funzione C
function C_Strlen (S : Interfaces.C.Strings.chars_ptr) return size_t
   with Import => True,
        Convention => C,
        External_Name => "strlen";

-- Esporta procedura Ada per chiamata da C
procedure Ada_Callback (Value : in int)
   with Export => True,
        Convention => C,
        External_Name => "ada_callback";
TIPI C EQUIVALENTI (Interfaces.C)
Ada (Interfaces.C)C equivalente
intint
unsignedunsigned int
charchar
C_floatfloat
doubledouble
size_tsize_t
Strings.chars_ptrchar*
UNCHECKED OPERATIONS
-- Conversione di tipo unsafe (come reinterpret_cast in C++)
with Ada.Unchecked_Conversion;
function To_Byte is new Ada.Unchecked_Conversion
   (Source => Character, Target => Byte);

-- Deallocazione manuale (free)
with Ada.Unchecked_Deallocation;
procedure Free is new Ada.Unchecked_Deallocation (Node, Node_Ptr);
Attenzione: Le operazioni Unchecked_* bypassano il sistema dei tipi. Usarle solo quando strettamente necessario e documentare il motivo.
COMPILAZIONE (GNAT / GCC)

GNAT (GNU Ada Translator) è il compilatore Ada open-source, parte di GCC. Alire è il package manager moderno per l'ecosistema Ada/SPARK.

# ─── Compilazione diretta ──────────────────────────
$ gnatmake main.adb                 # compila + linka in un passo
$ gnatmake -O2 -gnatn main.adb      # ottimizzato + inlining
$ gnatmake -gnata main.adb          # abilita assertions (Pre/Post)
$ gnatmake -gnatwa main.adb         # tutti i warning attivi
$ gnatmake -gnatVa main.adb         # tutti i validity checks

# ─── Compilazione separata ────────────────────────
$ gcc -c stack.adb                   # compila solo il body (.o)
$ gcc -c main.adb
$ gnatbind main.ali                  # risolve dipendenze
$ gnatlink main.ali                  # linka

# ─── Con GPRbuild (progetto complesso) ────────────
$ gprbuild -P myproject.gpr          # usa file di progetto GNAT
$ gprbuild -P myproject.gpr -Xmode=release

# ─── Con Alire (package manager) ──────────────────
$ alr init my_project --bin          # crea progetto eseguibile
$ alr init my_lib --lib              # crea progetto libreria
$ alr build                          # compila
$ alr run                            # compila e esegui
$ alr with gnatcoll                  # aggiungi dipendenza
FLAG GNAT IMPORTANTI
FlagSignificato
-gnataAbilita assertions, Pre/Post, Type_Invariant
-gnatwaTutti i warning
-gnatweWarning come errori
-gnatoOverflow check (default in GNAT)
-gnatpSopprime TUTTI i check (pericoloso, solo produzione ottimizzata)
-gnatVaTutti i validity check
-gnatnAbilita inlining inter-unità
-gnatlListing con codice sorgente
-gnatRMostra representation info (layout memoria)
-gnat2022Attiva features Ada 2022
-gnat2012Attiva features Ada 2012 (default in GNAT recenti)
-gnateDX=YDefinisce simbolo preprocessore
FILE DI PROGETTO (.gpr)
project My_Project is
   for Source_Dirs use ("src");
   for Object_Dir  use "obj";
   for Main        use ("main.adb");

   package Compiler is
      for Default_Switches ("Ada") use
         ("-gnatwa", "-gnata", "-O2", "-gnat2022");
   end Compiler;
end My_Project;
ATTRIBUTI COMUNI

Gli attributi ('Attribute) sono proprietà/operazioni predefinite su tipi e oggetti.

AttributoSi applica aRisultato
T'FirstTipo scalare / ArrayPrimo valore / primo indice
T'LastTipo scalare / ArrayUltimo valore / ultimo indice
T'RangeTipo scalare / ArrayT'First .. T'Last
T'LengthArrayNumero di elementi
T'Image (V)Tipo scalareConversione valore → String
T'Value (S)Tipo scalareConversione String → valore
T'Succ (V)Tipo discretoSuccessore
T'Pred (V)Tipo discretoPredecessore
T'Pos (V)Tipo discretoPosizione ordinale
T'Val (N)Tipo discretoValore dalla posizione
T'SizeTipo / OggettoDimensione in bit
T'AddressOggettoIndirizzo in memoria
T'AccessOggetto (aliased)Access value (puntatore)
T'Min (A,B)Tipo scalareMinimo tra A e B
T'Max (A,B)Tipo scalareMassimo tra A e B
T'DigitsFloating-pointCifre di precisione
T'ModulusTipo modularValore del modulo
T'ReduceArray/Iterabile (2022)Riduzione (fold)
STANDARD LIBRARY — PACKAGE PRINCIPALI
PackageContenutoDa
Ada.Text_IOI/O testuale (Put, Get, file)83
Ada.Strings.UnboundedStringhe a lunghezza variabile95
Ada.Strings.FixedOperazioni su String a lunghezza fissa95
Ada.Strings.MapsCharacter mapping e set95
Ada.Numerics.Elementary_FunctionsSin, Cos, Sqrt, Log, Exp...95
Ada.Numerics.Float_RandomGeneratore numeri casuali Float95
Ada.Numerics.Discrete_RandomGeneratore numeri casuali discreti95
Ada.CalendarData e ora83
Ada.Real_TimeOrologio monotono ad alta risoluzione95
Ada.Containers.VectorsArray dinamico (come std::vector)2005
Ada.Containers.Doubly_Linked_ListsLista bidirezionale2005
Ada.Containers.Hashed_MapsHashMap (come unordered_map)2005
Ada.Containers.Ordered_MapsMap ordinata (come std::map)2005
Ada.Containers.Hashed_SetsHashSet2005
Ada.Containers.Ordered_SetsSet ordinato2005
Ada.DirectoriesNavigazione filesystem2005
Ada.Environment_VariablesVariabili d'ambiente2005
Ada.Command_LineArgomenti da riga di comando95
Ada.ExceptionsInfo su eccezioni (nome, messaggio)95
Ada.StreamsStreaming di dati95
InterfacesTipi C, COBOL, Fortran95
SystemInfo sistema, Address, Storage_Elements83
GNAT.SocketsNetworking TCP/UDP (GNAT-specifico)
STRINGHE — UNBOUNDED E OPERAZIONI

Le String Ada sono a lunghezza fissa (array di Character). Per stringhe a lunghezza variabile si usa Unbounded_String.

UNBOUNDED_STRING
with Ada.Strings.Unbounded;
use  Ada.Strings.Unbounded;

S : Unbounded_String;
S := To_Unbounded_String ("Hello");
S := S & ", World!";  -- concatenazione

-- Conversioni
Len : Natural := Length (S);
Fix : String  := To_String (S);

-- Operazioni
Ch : Character := Element (S, 1);
Replace_Element (S, 1, 'h');
S := Head (S, 5);     -- primi 5 char
S := Tail (S, 3);     -- ultimi 3 char
OPERAZIONI SU STRING FISSE
with Ada.Strings.Fixed;
use  Ada.Strings.Fixed;

S : String (1..20);

-- Ricerca
Pos := Index (S, "abc");    -- 0 se non trovato
Cnt := Count (S, "x");

-- Trim spazi
T := Trim (S, Ada.Strings.Both);

-- Sostituzione
R := Replace_Slice
   (S, 3, 5, "XY");

-- Padding e allineamento
H := Head ("Hi", 10);  -- "Hi        "
T := Tail ("Hi", 10);  -- "        Hi"
ADA.CHARACTERS.HANDLING
with Ada.Characters.Handling; use Ada.Characters.Handling;

Is_Letter ('A');        -- True
Is_Digit ('3');         -- True
Is_Alphanumeric ('_'); -- False
To_Upper ('a');         -- 'A'
To_Lower ("HELLO");    -- "hello"
SLICING E CONCATENAZIONE
S : String := "Hello, World!";

-- Slicing (gli indici seguono il range della stringa)
Sub : String := S (1..5);       -- "Hello"
End_Part : String := S (8..13); -- "World!"

-- Concatenazione con &
Full : String := "Ada" & " " & "2022";  -- "Ada 2022"
WithChar : String := "X" & '!';          -- "X!" (String & Character)

-- Confronto (case-sensitive, ordine lessicografico)
if S = "Hello, World!" then ...   -- uguaglianza
if "abc" < "abd" then ...       -- True
CONVERSIONI STRING ↔ TIPI SCALARI
-- Numero → String
S1 : String := Integer'Image (42);      -- " 42" (spazio iniziale per il segno)
S2 : String := Float'Image (3.14);      -- " 3.14000E+00"

-- String → Numero
N : Integer := Integer'Value ("42");    -- 42
F : Float   := Float'Value ("3.14");   -- 3.14

-- Ada 2022: 'Image senza spazio iniziale per Integer
S3 : String := 42'Image;               -- "42" (Ada 2022+)
MAPS — TRADUZIONE CARATTERI
with Ada.Strings.Fixed; use Ada.Strings.Fixed;
with Ada.Strings.Maps;  use Ada.Strings.Maps;

-- Definire una mappa di traduzione
Vowel_Set : Character_Set := To_Set ("aeiouAEIOU");
Pos : Natural := Index (Source => "Hello",
                        Set    => Vowel_Set);  -- 2 ('e')

-- Translate: sostituisce caratteri
Map : Character_Mapping := To_Mapping
   (From => "aeiou", To => "AEIOU");
R : String := Translate ("ciao mondo", Map); -- "cIAO mOndO"
BOUNDED_STRING — ESEMPIO
with Ada.Strings.Bounded;

package Name_Strings is new
   Ada.Strings.Bounded.Generic_Bounded_Length (Max => 50);
use Name_Strings;

S : Bounded_String := To_Bounded_String ("Ada");
S := S & " Lovelace";            -- "Ada Lovelace"
L : Natural := Length (S);         -- 12
F : String  := To_String (S);      -- conversione a String fissa
Quale tipo scegliere? String fissa per dimensioni note a compile-time; Bounded_String per lunghezza variabile con tetto massimo (no heap); Unbounded_String per lunghezza totalmente dinamica (usa heap).
ADA.CONTAINERS — VECTORS, MAPS, SETS (Ada 2005+)
VECTORS (ARRAY DINAMICO)
with Ada.Containers.Vectors;

package Int_Vectors is new
   Ada.Containers.Vectors (Index_Type   => Natural,
                           Element_Type => Integer);
use Int_Vectors;

V : Vector;

V.Append (10);                -- aggiunge in coda
V.Append (20);
V.Append (30);
V.Prepend (5);               -- aggiunge in testa (Ada 2022)

Put (V.Length);                -- 4
Put (V.Element (0));           -- 5 (primo elemento)
Put (V (2));                   -- 20 (Ada 2012: indexing notation)

V.Replace_Element (1, 99);   -- V(1) := 99
V.Delete_Last;                 -- rimuove ultimo
V.Insert (2, 42);             -- inserisce 42 alla posizione 2

-- Iterazione
for E of V loop              -- Ada 2012: iterazione per elemento
   Put (E, Width => 0);
end loop;

for C in V.Iterate loop     -- iterazione per cursore
   Put (Element (C));
end loop;

V.Clear;                       -- svuota
HASHED_MAPS (HASH TABLE)
with Ada.Containers.Indefinite_Hashed_Maps;
with Ada.Strings.Hash;

package Name_Map is new
   Ada.Containers.Indefinite_Hashed_Maps
     (Key_Type        => String,
      Element_Type    => Integer,
      Hash            => Ada.Strings.Hash,
      Equivalent_Keys => "=");
use Name_Map;

M : Map;

M.Insert ("alice", 30);
M.Insert ("bob",   25);
M.Include ("alice", 31);   -- Insert o Replace (nessuna eccezione se esiste)

if M.Contains ("alice") then
   Put (M.Element ("alice"));  -- 31
end if;

M.Delete ("bob");

for C in M.Iterate loop
   Put_Line (Key (C) & " => " & Integer'Image (Element (C)));
end loop;
ORDERED_MAPS E SETS
-- Map ordinata per chiave (albero bilanciato)
with Ada.Containers.Ordered_Maps;
package Score_Map is new
   Ada.Containers.Ordered_Maps (Key_Type => Integer, Element_Type => Float);

-- Set ordinato
with Ada.Containers.Ordered_Sets;
package Int_Sets is new
   Ada.Containers.Ordered_Sets (Element_Type => Integer);
use Int_Sets;

S : Set;
S.Insert (10);
S.Insert (5);
S.Insert (10);   -- nessun effetto (duplicato)
-- S contiene {5, 10}
ContainerDefiniteIndefiniteAccesso
VectorVectorsIndefinite_VectorsO(1) per indice
ListaDoubly_Linked_ListsIndefinite_Doubly_Linked_ListsO(n) sequenziale
Hash MapHashed_MapsIndefinite_Hashed_MapsO(1) medio
Ordered MapOrdered_MapsIndefinite_Ordered_MapsO(log n)
Hash SetHashed_SetsIndefinite_Hashed_SetsO(1) medio
Ordered SetOrdered_SetsIndefinite_Ordered_SetsO(log n)
Definite vs Indefinite: Usare le versioni Indefinite quando il tipo dell'elemento è unconstrained (es. String). Le versioni Definite sono più efficienti per tipi a dimensione nota a compile-time.
CONTROLLED TYPES — RAII / FINALIZZAZIONE

I Controlled Types permettono di eseguire codice alla creazione, assegnamento e distruzione di un oggetto — il pattern RAII (Resource Acquisition Is Initialization) di Ada.

with Ada.Finalization;

package Smart_Ptrs is
   type Smart_Ptr is new Ada.Finalization.Controlled with private;

   -- Operazioni pubbliche
   function Create (Value : Integer) return Smart_Ptr;
   function Get    (Self : Smart_Ptr)  return Integer;

private
   type Int_Ptr is access Integer;

   type Smart_Ptr is new Ada.Finalization.Controlled with record
      Ptr : Int_Ptr := null;
   end record;

   -- Override delle primitive di finalizzazione
   overriding procedure Initialize (Self : in out Smart_Ptr);  -- alla creazione
   overriding procedure Adjust     (Self : in out Smart_Ptr);  -- dopo assegnamento (:=)
   overriding procedure Finalize   (Self : in out Smart_Ptr);  -- alla distruzione
end Smart_Ptrs;
PrimitivaQuando viene chiamataUso tipico
InitializeAlla creazione (se non inizializzato con aggregate)Allocare risorse
AdjustDopo un assegnamento := (sulla copia)Deep copy di risorse
FinalizeAlla fine dello scope o prima di riassegnamentoRilasciare risorse (free, close)
Limited_Controlled: Se il tipo è limited (non copiabile), estendere Ada.Finalization.Limited_Controlled — ha solo Initialize e Finalize (niente Adjust).
FEATURES ADA 2022 Ada 2022

Ada 2022 (ISO/IEC 8652:2023) introduce diverse funzionalità che rendono il linguaggio più espressivo mantenendo la sicurezza. Compilare con -gnat2022.

DECLARE EXPRESSION
-- Variabili locali in un'espressione (senza statement)
Area : Float :=
   (declare
       R : constant Float := Radius (Shape);
       Pi : constant := 3.14159_26535;
    begin
       Pi * R ** 2);
DELTA AGGREGATES
-- Copia un record/array modificando solo alcuni campi
type Config is record
   Port    : Positive := 8080;
   Debug   : Boolean  := False;
   Timeout : Duration := 30.0;
end record;

Default_Cfg : Config;
Debug_Cfg   : Config := (Default_Cfg with delta Debug => True, Port => 9090);

-- Funziona anche con array
A : array (1..5) of Integer := (1, 2, 3, 4, 5);
B : array (1..5) of Integer := (A with delta 3 => 99, 5 => 0);
-- B = (1, 2, 99, 4, 0)
TARGET NAME @ (AUTO-REFERENZA)
-- @ si riferisce alla variabile a sinistra dell'assegnamento
Count := @ + 1;                     -- equivale a: Count := Count + 1
Name  := To_Upper (@);               -- equivale a: Name := To_Upper (Name)
Rec.Field := @ * 2;                  -- equivale a: Rec.Field := Rec.Field * 2
Map.Reference ("key") := @ & "!";  -- evita doppia valutazione della chiave
'REDUCE ATTRIBUTE
-- Riduzione (fold) su array e iterabili
Sum   : Integer := [for I in 1..100 => I]'Reduce ("+", 0);       -- 5050
Prod  : Integer := [1, 2, 3, 4, 5]'Reduce ("*", 1);              -- 120

-- Con funzione custom
Max_Val : Integer := Data'Reduce (Integer'Max, Integer'First);
ARRAY AGGREGATES CON ITERATORE
-- Sintassi [ ] per aggregati (Ada 2022)
Squares : array (1..10) of Integer :=
   [for I in 1..10 => I ** 2];   -- [1, 4, 9, 16, ..., 100]

Evens : array (1..5) of Integer :=
   [for I in 1..5 => I * 2];    -- [2, 4, 6, 8, 10]
DICHIARAZIONI IN BLOCCHI SENZA DECLARE
-- Variabili dichiarate ovunque in sequenza di statement (non più solo dopo is/declare)
begin
   Put_Line ("Inizio");
   X : constant Integer := Compute_Value;  -- dichiarazione in-place
   Put (X);
end;
PARALLEL LOOP E PARALLEL BLOCK
-- Loop parallelo (iterazioni indipendenti)
parallel
for I in 1..1_000 loop
   Result (I) := Heavy_Compute (I);
end loop;

-- Blocco parallelo (sezioni indipendenti)
parallel do
   A := Compute_A;
and
   B := Compute_B;
end do;

-- Riduzione parallela (Ada 2022 + 'Reduce)
Total : Integer := [parallel for I in 1..1_000_000 => F(I)]'Reduce("+", 0);
Compilazione: Per abilitare tutte le features Ada 2022, usare gnatmake -gnat2022 o -gnat2022 nel file .gpr. GNAT 13+ supporta la maggior parte delle features.
SPARK — VERIFICA FORMALE

SPARK è un sottoinsieme verificabile di Ada. Con gli strumenti GNATprove, si può provare matematicamente l'assenza di runtime errors (overflow, divisione per zero, bounds check).

package Safe_Math
   with SPARK_Mode => On
is
   function Safe_Add (A, B : Integer) return Integer
      with Pre  => (A >= 0 and then B >= 0
                    and then A <= Integer'Last - B),
           Post => Safe_Add'Result = A + B;

   function Abs_Value (X : Integer) return Natural
      with Pre  => X > Integer'First,   -- evita overflow di abs(Integer'First)
           Post => (if X >= 0 then Abs_Value'Result = X
                     else Abs_Value'Result = -X);
end Safe_Math;
# Verifica formale
$ gnatprove -P myproject.gpr --level=2
# Se tutte le prove passano → assenza GARANTITA di runtime errors nel codice SPARK
SPARK è usato in: avionics (DO-178C Level A), ferroviario (EN 50128 SIL4), nucleare, automotive, difesa. Quando il software non può fallire.