Documentation Ada Détaillée

Un guide exhaustif pour maîtriser la conception robuste et la syntaxe du langage Ada.

1. Introduction & Philosophie

Origine

Créé à l'origine par le Département de la Défense des États-Unis (DoD) dans les années 1980, Ada a été conçu pour unifier le développement de systèmes critiques. Son nom rend hommage à Ada Lovelace, la première programmeuse de l'histoire.

Philosophie de conception

  • La lisibilité prime sur l'écriture : Le code est lu beaucoup plus souvent qu'il n'est écrit. La syntaxe évite les symboles cryptiques au profit de mots-clés clairs (pas d'accolades, mais des begin ... end).
  • Typage statique extrêmement fort : Le compilateur est votre meilleur ami et votre pire ennemi. Il détecte un maximum d'erreurs à la compilation plutôt qu'à l'exécution.
  • Sûreté et Fiabilité : Débordements de tableaux, fuites de mémoire et accès à des pointeurs nuls sont systématiquement contrôlés (ou rendus très difficiles à produire).

Anatomie d'un programme

with Ada.Text_IO; use Ada.Text_IO;

procedure Mon_Programme is
   -- Zone de déclaration : variables, constantes, types locaux
   Message : constant String := "Bienvenue en Ada !";
begin
   -- Zone d'exécution : algorithme principal
   Put_Line (Message);
end Mon_Programme;
2. Système de Types Avancé

En Ada, un type n'est pas juste un format de mémoire (comme int en C), c'est une définition sémantique stricte. Le compilateur interdit de mélanger deux types différents, même s'ils partagent la même représentation sous-jacente.

Types Scalaires (Entiers et Flottants)

Vous définissez l'intervalle de validité. Si la variable sort de cet intervalle, une erreur est levée.

type Jour_Du_Mois is range 1 .. 31;
type Pourcentage is digits 3 range 0.0 .. 100.0; -- Précision de 3 chiffres significatifs

J : Jour_Du_Mois := 15;
-- J := 32; -- Provoquera une erreur (Constraint_Error)

Énumérations

Très puissantes en Ada, elles permettent de définir des états précis.

type Feux_Tricolores is (Rouge, Orange, Vert);
Etat : Feux_Tricolores := Rouge;

Sous-types (Subtypes)

Contrairement à un nouveau type, un subtype reste compatible avec le type parent, mais ajoute une contrainte (souvent de plage).

subtype Jour_Ouvrable is Jour_Du_Mois range 1 .. 5;
-- Compatible avec Jour_Du_Mois, mais limité à 5.

Tableaux (Arrays)

Les indices ne commencent pas obligatoirement à 0.

type Semaine is array (1 .. 7) of Float;
type Tab_Temperatures is array (Jour_Du_Mois) of Float; -- L'indice est le type défini plus haut !

Mes_Notes : Semaine := (15.5, 12.0, 18.0, others => 0.0); -- "others" remplit le reste

Enregistrements (Records / Structs)

Permet de regrouper des données hétérogènes.

type Personne is record
   Nom    : String (1 .. 50);
   Age    : Integer;
   Actif  : Boolean := True; -- Valeur par défaut
end record;

Employe : Personne := (Nom => "Alice" & (6..50 => ' '), Age => 30, Actif => True);
3. Structures de Contrôle

Instructions Conditionnelles (If / Elsif)

if Valeur < 0 then
   Put_Line ("Négatif");
elsif Valeur = 0 then
   Put_Line ("Nul");
else
   Put_Line ("Positif");
end if;

Choix Multiple (Case)

Le case en Ada est exhaustif. Le compilateur vous obligera à traiter tous les cas possibles ou à utiliser when others.

case Etat is
   when Rouge  => Stopper_Vehicule;
   when Orange | Vert => Avancer; -- Le pipe '|' signifie "ou"
   when others => null; -- "null" indique explicitement de ne rien faire
end case;

Les Boucles (Loops)

Boucle simple (infinie) avec sortie :

loop
   Saisie := Get_Line;
   exit when Saisie = "fin"; -- "exit when" permet de casser la boucle élégamment
end loop;

Boucle For : (L'itérateur I est automatiquement déclaré et en lecture seule).

for I in 1 .. 10 loop
   Put_Line ("Itération" & Integer'Image (I));
end loop;

-- Parcours inversé
for I in reverse 1 .. 10 loop
   null;
end loop;

Boucle While :

while Compteur < 100 loop
   Compteur := Compteur + 1;
end loop;
4. Procédures & Fonctions

Ada distingue strictement l'action (qui modifie un état) du calcul (qui retourne une valeur).

Modes de Paramètres

  • in : Le sous-programme peut lire mais pas modifier la variable (mode par défaut).
  • out : Le sous-programme doit affecter une valeur à cette variable avant de se terminer.
  • in out : La variable contient une valeur initiale qui sera lue puis modifiée.

Procédure

procedure Echanger (A, B : in out Integer) is
   Temp : Integer;
begin
   Temp := A;
   A := B;
   B := Temp;
end Echanger;

Fonction

Une fonction ne peut avoir que des paramètres en mode in (pour éviter les effets de bord).

function Est_Pair (Nombre : Integer) return Boolean is
begin
   return Nombre mod 2 = 0;
end Est_Pair;

Surcharge (Overloading)

Vous pouvez définir plusieurs fonctions portant le même nom, tant que leurs signatures (paramètres ou type de retour) diffèrent.

procedure Afficher (Valeur : Integer);
procedure Afficher (Valeur : Float);
procedure Afficher (Texte : String);
5. Modularité (Packages)

Les packages sont la base de l'architecture logicielle en Ada. Ils permettent l'encapsulation et la réutilisabilité.

La Spécification (.ads) : Le Contrat Public

Ce fichier déclare ce qui est accessible aux autres parties du programme.

package Math_Operations is
   Pi : constant Float := 3.14159;
   function Ajouter (A, B : Integer) return Integer;
end Math_Operations;

Le Corps (.adb) : L'Implémentation Privée

Ce fichier contient le code réel. Les détails internes sont cachés.

package body Math_Operations is
   
   -- Fonction locale (invisible de l'extérieur)
   function Verifier_Positif (N : Integer) return Boolean is ...

   function Ajouter (A, B : Integer) return Integer is
   begin
      return A + B;
   end Ajouter;

end Math_Operations;

Utiliser un Package

with Math_Operations; -- Rend le package visible
use Math_Operations;  -- Permet d'utiliser Ajouter() au lieu de Math_Operations.Ajouter()

Types Privés (Encapsulation)

Pour cacher la structure interne d'un type aux utilisateurs du package :

package Banque is
   type Compte is private;
private
   type Compte is record
      Solde : Float := 0.0;
   end record;
end Banque;
6. Gestion des Exceptions

Ada possède un mécanisme natif de gestion d'erreurs (équivalent au Try/Catch).

Déclarer et Lever une Exception

Solde_Insuffisant : exception;

procedure Retirer (Montant : Float) is
begin
   if Montant > Solde then
      raise Solde_Insuffisant;
   end if;
end Retirer;

Traiter une Exception

Le traitement se place à la toute fin d'un bloc (sous-programme ou bloc declare).

begin
   Retirer (5000.0);
exception
   when Solde_Insuffisant =>
      Put_Line ("Erreur : Vous n'avez pas les fonds.");
   when Constraint_Error =>
      Put_Line ("Erreur mathématique ou débordement.");
   when others =>
      Put_Line ("Une erreur inattendue est survenue.");
end;
7. Programmation Orientée Objet (Tagged Types)

L'OO en Ada est implémentée via l'extension des records appelés Tagged Types.

La classe de base (Type Tagged)

type Forme is tagged record
   X, Y : Float;
end record;

-- Méthode primitive liée à 'Forme'
procedure Afficher (F : Forme) is
begin
   Put_Line ("Position X, Y");
end Afficher;

L'héritage (Type Extension)

type Cercle is new Forme with record
   Rayon : Float;
end record;

-- Redéfinition (Overriding) de la méthode
procedure Afficher (C : Cercle) is
begin
   Put_Line ("Cercle de rayon " & Float'Image(C.Rayon));
end Afficher;

Le Dispatching Dynamique (Polymorphisme)

Ada gère le polymorphisme avec les types 'Class.

procedure Traiter_Forme (F : Forme'Class) is
begin
   Afficher (F); -- Appellera Afficher(Forme) ou Afficher(Cercle) dynamiquement
end Traiter_Forme;
8. Concurrence Native (Tasking)

Ada est l'un des rares langages à intégrer le temps réel et le multi-threading directement dans sa syntaxe.

Les Tâches (Tasks)

Une tâche s'exécute en parallèle dès qu'elle est instanciée.

task Traitement_Fond;

task body Traitement_Fond is
begin
   loop
      Put_Line ("Je tourne en arrière-plan...");
      delay 1.0; -- Pause de 1 seconde
   end loop;
end Traitement_Fond;

Objets Protégés (Protected Objects)

Pour éviter les problèmes d'accès concurrent (Race Conditions), les objets protégés garantissent que les données sont lues/écrites par une seule tâche à la fois de manière sécurisée (MutEx natif).

protected Compteur_Securise is
   procedure Incrementer;
   function Lire return Integer;
private
   Valeur : Integer := 0;
end Compteur_Securise;

protected body Compteur_Securise is
   procedure Incrementer is
   begin
      Valeur := Valeur + 1;
   end Incrementer;

   function Lire return Integer is
   begin
      return Valeur;
   end Lire;
end Compteur_Securise;
9. Généricité (Templates)

Permet d'écrire des algorithmes ou des structures de données (comme une liste ou un arbre) valables pour n'importe quel type de donnée, sans avoir à réécrire le code.

Définir une procédure générique

generic
   type Element is private; -- Fonctionne avec n'importe quel type
procedure Echanger_Generique (A, B : in out Element);

procedure body Echanger_Generique is
   Temp : Element := A;
begin
   A := B;
   B := Temp;
end Echanger_Generique;

Instancier le composant générique

Pour l'utiliser, il faut créer une version spécifique à la compilation :

procedure Echanger_Entiers is new Echanger_Generique (Element => Integer);
procedure Echanger_Flottants is new Echanger_Generique (Element => Float);

-- Utilisation :
X, Y : Integer := 5;
Echanger_Entiers (X, Y);
10. Bibliothèques Standard Fréquentes
  • Ada.Text_IO : Lecture/écriture console (Put, Get_Line).
  • Ada.Integer_Text_IO : Lecture/écriture d'entiers simplifiée.
  • Ada.Float_Text_IO : Lecture/écriture de flottants simplifiée.
  • Ada.Strings.Unbounded : Chaînes de caractères dynamiques de longueur variable (l'équivalent de std::string en C++).
  • Ada.Numerics.Discrete_Random : Génération de nombres aléatoires pour les jeux ou simulations.
  • Ada.Real_Time : Horloges et délais précis (indispensable pour l'embarqué temps réel).
  • Ada.Directories : Manipulation du système de fichiers, création de dossiers, vérification de l'existence de fichiers.