Enseigner Ada

(pourquoi ?,    à qui ?,    comment !)

Choisir un langage : entre le tentant et le raisonnable !                   


Version 3.2 (janvier 2005). Ont contribué à la rédaction de ce document (par ordre d'apport)
D. Feneuille (IUT), J.P. Rosen (Adalog), S. Tardieu (ENST), S. Rivière (Rochebrune), P. Obry (EDF), D. Minguillon (CNES),
P. Valarcher (DEUG), Y. Kermarrec (ENST Bretagne), P. Pignard , A. Charlet (ACT), L. Draghi (Thalès), L. Pautet (ENST), L. Zaffalon (EIG), P. Bréguet (EIVD), G. Canesi (CNAM) C. Kaiser (CNAM), J.F Peyre (CNAM) Attention pour les adresses électroniques supprimez les espaces autour du signe @ !! Spam oblige !


Résumé

    à l'initiative de l'association Ada-France, ce texte est une réflexion sur les qualités pédagogiques (mais aussi professionnelles) du langage de programmation Ada normalisé en 1983, mais surtout, joliment réactualisé en 1995 ce qui lui a redonné une longueur d'avance avec les plus actuels. Les arguments développés dans ces lignes sont ceux de praticiens francophones (pédagogues ou professionnels) convaincus de leur choix Ada et qui, parfois, sont affligés de constater que l'on enseigne, plus volontiers, la programmation avec un langage que l'on maîtrise mieux, et/ou avec ce qui est plus « à la mode » ; éternel choix entre le sérieux et ... le tentant !

    Quand on enseigne l'informatique (sauf à viser le développement de petits modules sans lendemain) on ne peut faire l'impasse sur la mise en pratique des préceptes du génie logiciel (souvent cités dans les cursus mais, hélas, pas toujours mis en application). La démarche génie logiciel implique de faire le choix d'enseigner, notamment à travers le langage, la qualité : c'est à dire en quelques mots faire : propre, rigoureux, fiable, lisible, portable, maintenable, réutilisable, extensible (donc modulaire et, si nécessaire, objet), et si possible (ce qui n'est pas négligeable) enseigner gratuit. Dans le cas où l'on souhaite toutes ces propriétés en même temps les langages candidats se font rares.

    Ce document, créé, avant tout, dans un but pédagogique, ne prétend pas présenter le langage Ada. Des pistes pour cela seront proposées (sites, cours, livres, didacticiel, etc.) voir le chapitre les aides et les outils (dans le plan ci dessous). Ce texte s'adresse bien sûr aux enseignants informaticiens (même débutants) mais surtout aux décideurs pédagogiques (directeurs d'enseignement, prescripteurs de formation dans l'industrie et la recherche). Les praticiens du langage Ada convaincus de ses qualités n'y verront que des évidences mais ils peuvent à tout moment réagir pour améliorer ou amender nos argumentations (contacts).

Abstract :

On the initiative of the Ada-France association, this text is a reflection on educational (but also professional) qualities of the programming language Ada normalized in 1983, but especially, finely updated in 1995 ; this standard gave to Ada an advance on rival languages. Arguments developed in these lines are those of the French-speaking practitioners (teachers or professionals) convinced of their choice of Ada and who, sometimes, are saddened to notice that one teaches, more gladly, programming with a language which is better known, and\or with what is "more fashionable"; the eternal choice between seriousness and  attractiveness !

    When one teaches data processing (outside the development of small modules without future) one cannot escape from the application of the rules of software engineering (often quoted in programme of education but, regrettably, not always applied).The "Software engineering” method implies to choose to teach, notably through the language, quality : in a few words : being clean, rigorous, reliable, legible, portable, maintenable, reusable, extensible (therefore modular and, if need be, object-oriented), and if possible (what is not unimportant) to teach free. If one wishes all these properties at the same time languages candidates are indeed rare.

This document, created, above all , for an educational purpose, does not claim to present the Ada language. Tracks for it will be suggested (sites, courses, books, educational software, etc.) see the chapter “helps and tools” (in the outline below). This text is intended naturally for computer science teachers (even novice ones) but especially to the educational decision-makers (directors of education, responsibles of training in industry and research). The practitioners of the Ada language who are already convinced of the qualities will see there only obvious material, but they can at any time react to improve or to amend our argumentations (contacts).


 

Retour page perso D. Feneuille

Retour site Ada France

Plan :


Introduction

    Le langage Ada a été conçu à l'initiative du D.O.D. (le département de la défense des USA) pour fédérer plus de 400 langages ou dialectes utilisés par cet organisme dans les années 1970 ! Des réunions et des documents de comités d'experts vont se succéder de 1975 à 1983 (appel d'offres, cahier des charges, choix, élection des projets et norme) pour présenter un langage généraliste, unificateur, normalisé et supportant les préceptes du génie logiciel : Ada83. Les premiers compilateurs (1985) sont onéreux mais ... respectent la norme ! (norme devenue internationale en 1987). Ada commence à faire ses preuves de fiabilité, de robustesse mais, a des défauts de jeunesse. De 1990 à 1995 la révision de la norme aboutit à Ada95, qui corrige les petits défauts, comble un gros manque en rendant le langage complètement objet (Ada est le premier langage objet normalisé). Ada95 ajoute ainsi son lot de nouveautés toujours inédites 10 ans après. Une nouvelle révision est en cours (nommée Ada0Y ; Y = 5 donc sûrement pour 2005) ce qui montre la vitalité et la pérennité du langage.

    Aujourd'hui (en 2003) Ada ne nous semble pas avoir la place qu'il mérite notamment dans les premiers apprentissages de l'informatique où l'on doit mêler la programmation elle même avec la bonne pratique de la programmation. Depuis longtemps Ada peut largement remplacer Pascal l'excellent langage pédagogique. Paradoxalement on trouve Ada plus volontiers enseigné dans des formations de très haut niveau car, là encore, il permet d'enseigner de façon claire, cette fois des concepts qualifiés de plus ardus.

    Faut-il enseigner (comme c'est trop le cas) les langages les plus récents ou les plus répandus (C/C++ notamment, voire Java pour être plus clairs), même si ces derniers semblent peu adaptés à l'apprentissage d'une bonne pratique ? Si la réponse est affirmative, et sous forme de boutade, il faut sacrer TF1 meilleure chaîne de télévision française, puisqu'elle est la plus regardée (ou encore si j'osais Windows le meilleur S.E. puisque le plus utilisé!). La modernité n'est pas un objectif pédagogique. Notons, comme contre exemple, que Java ne dispose toujours pas de la généricité (certes annoncée dans la version 1.5, mais déjà opérationnelle depuis 20 ans avec Ada83). La généricité est un concept essentiel pour la réutilisation

    En général les détracteurs d'Ada (enseignants ou professionnels) l'ont peu ou mal utilisé et confessent, volontiers, s'être arrêtés dans leurs tests, irrités par la rigueur du compilateur. Rigueur à laquelle ils ne sont pas habitués et qui reste (nous le montrerons), justement, la qualité essentielle pour un développement fiable.

    Ada est encore bien utilisé (voire incontournable) en avionique et en informatique embarquée (fusée Ariane par exemple) ainsi que pour le contrôle de trafic (aérien, ferroviaire) où la fiabilité est cruciale. Il est aussi apprécié quand le code à développer est conséquent (donc très difficile à maintenir). Mais il n'en reste pas moins qu'actuellement peu de petites ou moyennes entreprises admettent utiliser Ada. Ou alors (comme le signale J.P. Rosen) ces entreprises cachent l'utilisation d'Ada comme on garde un secret de fabrication ! En effet, même pour des applications plus modestes, les gains de productivité avec Ada sont prouvés et très significatifs.

    Les enseignants en informatique soucieux de faire développer du code de qualité pourront utiliser Ada qui est l'aboutissement des langages procéduraux, Ada, longtemps réservé aux applications de très haute technologie, est aujourd'hui enfin accessible aux moins fortunés. Un compilateur gratuit, ouvert et portable (GNAT) permet (notamment aux universitaires et aux autodidactes) de s'y frotter et ... d'adopter le langage pour une formation (ou une culture) informatique de qualité (voir dans le chapitre Les aides et les outils : les compilateurs).

retour au plan

Retour page perso D. Feneuille

Retour site Ada France

Le génie logiciel

    Dès les années 1970 on parle, déjà, de la crise du logiciel (et, aujourd'hui, le problème est récurrent et même encore plus préoccupant) : coût de développement dépassé ou difficile à prévoir, délais non respectés, livraison non conforme aux spécifications, programmes trop gourmands, peu fiables, modifications souvent impossibles, etc. Passons en revue, succinctement, quelques critères ou propriétés que doit satisfaire une application conséquente et de qualité. Le décor ainsi planté permettra de mettre en évidence dans le chapitre suivant les points forts du langage Ada satisfaisant aux objectifs soulevés.

retour au plan

Retour page perso D. Feneuille

Retour site Ada France

Les concepts bien illustrés

Ce chapitre est un survol rapide de quelques points forts du langage Ada qui permettent de discipliner le processus de développement et satisfaire ainsi les préceptes du génie logiciel. Le lecteur averti du langage pourra évidemment sauter ces illustrations ou nous en signaler d'autres.

Typage

Ada propose peu de types prédéfinis (dits standard ou primitifs) notons pour l'essentiel les types : caractère, chaîne, booléen, numérique entier et numérique réel (à virgule flottante). Leur implémentation n'est pas spécifiée par la norme et de ce fait il est recommandé de définir, soi même, ses propres types même les plus élémentaires et notamment les numériques (entiers, réels flottants et même réels fixes) gage d'une programmation plus sûre (portabilité notamment). Ada offre une puissance inégalée pour la déclaration de nouveaux types (et pas forcément numériques). 
Ainsi la déclaration
type T_Température is range -20..55; 
créé une famille d'objets numériques entiers dont les valeurs sont contraintes entre les bornes -20 et 55. Cette déclaration insère dans le code une connaissance du domaine qui reste habituellement dans les commentaires, ou dans des documents, ou... nulle part. Cette déclaration est portable (le range de T_Température ne dépend pas de la plate-forme de compilation) et, en plus, les débordements sont vérifiés dans le code généré. Ada est fortement typé ce qui interdit de façon implicite les mélanges (accidentels ou voulus). Plus de détail ?

On pourra voir aussi, en annexe, l'exemple (qui suit celui ci : travail au niveau du bit) où la spécialisation du type déclaré permet de garder une maîtrise sémantique de haut niveau tout en effectuant des opérations très pointues, détaillées et ... transparentes.

retour au plan

Encapsulation

Cette propriété, déjà essentielle dans l'antique T.A.D. (Type Abstrait de Données) des années 80, reste d'actualité avec les classes et les objets. Il s'agit de rendre, par une déclaration spécifique, étroitement solidaires les données d'un composant logiciel et les opérations associées. On parle respectivement aujourd'hui de données membres et de méthodes. En Ada cette enveloppe logicielle est réalisée avec les paquetages (package). Mais contrairement à Java (qui reprend ce concept 20 ans après !) il s'agit, en Ada, d'une entité bien concrète puisque déclarée dans un fichier propre. Cette propriété est le gage d'une grande fédération des concepts où rien n'est éparpillé. Le paquetage est resté avec Ada95 la structure fondamentale du langage car c'est une technique robuste et élégante de factorisation du code. Voir en annexe un exemple simple de paquetage.

retour au plan

« Spécifications » et réalisation

Le paquetage Ada (structure idéale d'un composant logiciel) abrite ces deux entités bien distinctes (généralement dans deux fichiers). Les déclarations package d'une part et package body d'autre part sont les labels de ces deux entités (respectivement spec et réalisation). La partie spec (pas tout à fait des spécifications ! mais plus sûrement un contrat) présente uniquement les déclarations (données et sous programmes). Le corps du paquetage réalisera, quant à lui, le contrat proposé par les spec. Toute nouvelle entité (sous programme ou paquetage) s'appuyant sur un paquetage déjà spécifié annonce cette dépendance avec with. Le compilateur ne se réfère alors qu'à la partie spec pour contrôler la syntaxe de la nouvelle entité. Le codage de la réalisation peut être différée. Cette séparation incite à prototyper sans penser implémentation et cette technique de développement est très importante. Dans l'enseignement de l'informatique ce procédé permet d'obliger les étudiants à réfléchir avant de coder et c'est le langage (et le compilateur) qui apportent aux enseignants une aide précieuse pour ce défi pédagogique. Ada fournit aux novices, des bases solides que ceux ci pourront transgresser ou mettre à profit dans d'autres langages mais en connaissance de cause (et non par ignorance). Par exemple dans la définition des sous programmes la portée et la direction des informations échangées est très claire. Le passage des arguments pour les procédures est précisé dans le prototypage. (mentions In, Out, ou In Out). Notons qu'une fonction Ada reste une fonction (elle accepte des paramètres en entrée et fournit un unique résultat en sortie), Pour un novice, ces notions de base apparaissent donc très clairement (ce qui rentre, ce qui sort, ce qui a été modifié, la notion de fonction et de procédure). Les impacts sur la modification des paramètres lors de l'utilisation d'une procédure ou d'une fonction externe sont tout aussi clairs.

De manière connexe on peut insister sur l’incidence de la normalisation et des contrôles à la compilation : l’existence d’outils généraux  de manipulation de programme et d’aide au développement en amont et en aval du langage. On notera aussi l’importance d’ASIS pour travailler au niveau des spécifications ou de la validation, et  les outils permettant de naviguer conjointement dans le programme et son modèle (programme Ada et réseaux de Petri, spécification et programme, débourrage et navigation dans les sources). On verra enfin avec intérêt le pragma avec assertions.(voir ci dessous le chapitre des exceptions) qui permet d'imposer aux étudiants dans leur code des contrôles qui sont des éléments de preuve de validité des algorithmes

Voir en annexe un exemple de paquetage

retour au plan

Généricité

Le T.A.D., aussi que la classe (voir plus loin), déclarés dans un paquetage (et intimement caractérisés par ce paquetage) peuvent se dériver (on y reviendra) mais aussi peuvent être paramétrés (on paramètre un paquetage comme on paramètre traditionnellement un sous programme). En Ada ces paramètres (dits de généricité) sont aussi complexes qu'on le souhaite. Les paramètres vont des très traditionnelles (constantes ou variables) en passant par les types, les sous programmes et jusqu'aux paquetages eux mêmes génériques ! Ce profond degré d'abstraction est absolument remarquable. En Ada la mise en oeuvre de la généricité (déclaration, instanciation et utilisation) est très simple et élégante (donc facile à enseigner). Les paquetages génériques en Ada sont compilés d'autorité sans attendre qu'ils soient instanciés ce qui n'est pas le cas des templates C++. Cette compilation autoritaire permet de valider le contrat générique et d'assurer que toute instance respectant le contrat compilera et fonctionnera comme prévu. La généricité permet et facilite la réutilisation et c'est même la technique la plus sûre pour réutiliser de façon fiable.

retour au plan

Conception hiérarchique

Avec les paquetages, structure idéale pour construire T.A.D.(vu plus haut) ou les classes (voir plus bas), on peut construire avec Ada95 des familles de paquetages en allant d'une structure la plus simple vers (de proche en proche) la plus complète. Les paquetages fils (nouvellement créés) s'appuient naturellement sur les contrats (spec) des ascendants et permettent d'ajouter des fonctionnalités sans remettre en cause le travail de conception déjà élaboré. Les paquetages « officiels Ada » (fort nombreux et très utiles, voir plus bas) paquetages fournis avec le compilateur possèdent cette structure hiérarchique. Cette manière de travailler (faire modeste et essentiel d'abord, puis, de plus en plus détaillé et complet) est évidemment  recommandée dès que les logiciels sont conséquents et cette méthode facilite des développements séparés et/ou en équipes. Et, point remarquable, elle rend inutiles les tests de non régression sur le paquetage parent qui, lui, n'a pas changé. Cette technique ne nécessite a priori aucune dérivation contrairement aux langages C++ ou Java. Elle permettra aussi de fabriquer des classes (voir plus loin) mais alliée cette fois à la dérivation. Voir en annexe un exemple de paquetage fils.

retour au plan

Exceptions

Les exceptions sont présentes dans le langage dès Ada83. Ce concept est évidemment incontournable en programmation et permet de prendre en compte les « anomalies » pendant le déroulement d'une application. La mise en oeuvre Ada des exceptions (déclaration, déclenchement et traitement) nous semblent d'une grande facilité et donc très agréable à enseigner. Ada95 a considérablement amélioré ce bagage et permet des traitements plus profonds (un peu moins simples cependant à appliquer). Dans le même esprit nous signalons une propriété didactique d'importance à savoir la possibilité de mettre en place, dans le code, des assertions. Il s'agit d'un pragma (une directive pour le compilateur) que l'on peut activer optionnellement à la génération du code. A l'exécution quand une assertion n'est pas satisfaite une exception système bien identifiée est levée. On peut ainsi imposer aux étudiants dans leur code des contrôles qui sont des éléments de preuve de validité des algorithmes. Cette propriété n'est, à notre avis, pas assez utilisée même si elle reste moins élaborée que dans le langage Eiffel par exemple. 

retour au plan

Approche modulaire

Ce concept appartient aux techniques de C.O.O. (Conception Orientée Objet) chères à Grady Booch qui l'a bien illustrée avec Ada83. A priori, quand on reste à ce stade de conception (et c'est très souvent suffisant dans de nombreux développements) il n'est pas nécessaire de faire de l'objet « vrai ». C'est à dire qu'il est souvent inutile de prévoir des structures susceptibles d'être étendues par dérivation (donc faire de la conception par analogie). Cependant, si tel est le cas, Ada95 a une réponse pour faire des classes et des objets (avec la déclaration tagged voir plus loin). Si l'on reste au niveau de l'approche modulaire, alors, le paquetage (toujours lui !), déclarant une structure de données (de préférence privée) avec les méthodes (fonctionnalités) associées, rendra tous les services attendus. Comme on l'a vu plus haut on peut étendre les fonctionnalités avec les hiérarchies de paquetages sans dériver (dériver est possible en Ada mais pas obligatoire). Comme le concept de dérivation (et notamment la liaison dynamique qui va avec) n'est pas aussi facile à assimiler qu'il y parait Ada permet élégamment de retarder cette difficulté tout en permettant des développements avec tous les préceptes suggérés par le génie logiciel.

retour au plan

Classes et objets

Une lecture superficielle du manuel de référence Ada (ah la norme !) pourrait laisser croire que Ada ne permet pas les objets puisque aucun constructeur syntaxique class n'est présent dans le vocabulaire du langage. La réalité est tout autre : ce constructeur (cher à C++ et Java) n'est pas utile avec Ada95. Pour faire des classes et donc des objets il suffit de reprendre le concept d'encapsulation, vu avec les paquetages, et de déclarer la première structure de données (racine) avec l'appellation tagged. En clair tout type « taggué (ou plutôt étiqueté) » est susceptible d'être dérivé par extension et cet héritage caractérise la structure de classe. On peut intelligemment mêler cette technique de conception avec l'utilisation des hiérarchies de paquetages vue plus haut permettant, ainsi, encore plus de souplesse et d'élégance dans les développements. Notons cependant, que l'héritage multiple n'est pas prévu, en effet les concepteurs du langage n'ont pas jugé utile d'ajouter une construction spécifique pour l'héritage multiple, car trop complexe pour un usage réduit (les bons exemples d'héritage multiples sont très rares). Par contre la conjonction « dérivation et généricité » permet de résoudre les cas de « mixing inheritance » beaucoup moins rares. Voir en annexe un exemple de classe.

retour au plan

Programmation d'activités concurrentes

On touche là à un grand moment de bonheur didactique. Avec quelle élégance Ada permet de concevoir et de réaliser facilement la programmation de processus concurrents ! Les tâches (avec Ada83 déjà !) et les objets protégés permettent d'illustrer donc de faire comprendre et assimiler des concepts forts importants et pas toujours évidents en temps réel et en informatique répartie tels que synchronisation et/ou échange d'information entre activités parallèles, exclusion mutuelle, partage de ressources communes, etc. De façon plus détaillée disons que :

La possibilité de faire apparaître explicitement l’architecture opérationnelle en la « mappant » sur des tâches permet de suivre de façon claire le comportement et le « work flow » d’une application. C’est un aspect très utile pour le temps réel entre autre. Cela n’empêche pas de structurer aussi l’accès à l’information en termes d’objets (objets passifs ou objets pouvant contenir des tâches quand il s’agit d’un objet « serveur »).

Un ensemble de choix judicieux à la conception du langage ont fait de l’objet protégé la meilleure réalisation du concept de moniteur (introduit par C.AR. Hoare et P. Brinch Hansen), loin devant toute autre, même plus récente comme Java. Notons l’évaluation des conditions d’attente avant toute section critique de code, l’évaluation des conditions de réveil à la fin de chaque section critique, la clause « requeue » qui permet de construire des séquences de sections critiques pour une même tâche tout en permettant d’y intercaler les sections critiques d’autres tâches, la priorité donnée aux tâches déjà utilisatrices de l’objet protégé. Tout cela permet de traiter les problèmes de synchronisation à un haut niveau d’abstraction, celui d’automates à files d’attente, et permet de les traiter tous au même niveau (sans introduire des « wait » ou « signal » ou encore « notify », de bas niveau, avec des effets imprévisibles dépendant de l’implantation de l’ordonnanceur du système hôte). Cela facilite aussi la validation des algorithmes concurrents et leur mise au point. On pourra consulter des exemples de programmation concurrente. À notre connaissance, ces exemples ne sont ni dans le manuel de référence, ni dans des ouvrages de cours. Ces exemples ont été choisis pour montrer la simplicité et la puissance de l’objet protégé. Voir aussi des articles dans http://www.ada-france.org/article42.html .

La même remarquable simplicité se retrouve dans la programmation distribuée avec Ada où la notion d'activité concurrente est étendue aux machines sur un réseau (voir un exemple élémentaire).

retour au plan

Retour page perso D. Feneuille

Retour site Ada France

Pour quels apprenants ?

On trouvera dans les paragraphes ci dessous des témoignages et des contributions d'enseignants utilisant Ada pour leurs enseignements et appréciant ses qualités dans leur différents cursus (forts variés). La Suisse francophone qui est très active (voire même à la pointe de la diffusion d'Ada) présentera ses propositions très intéressantes. 

Non informaticiens

Enseigner l'informatique à l'intention d'étudiants dont la formation essentielle n'est pas l'informatique a été tenté avec satisfaction par Michel Gauthier (en premier cycle à Limoges) et P. Tarroux en DEA Sciences cognitives à Paris-Sud (Orsay). Ce dernier cite une introduction à l'informatique avec Ada et Java comme supports comparés. L'expérience est instructive concernant la légèreté de Java et la rigueur d'Ada.  retour au plan

DEUG

Le langage Ada est utilisé comme support pour les 4 cours d'informatique (sur les 4 semestres) du DEUG MIAS au centre universitaire d'Évreux. Les premiers cours portent sur l'algorithmique classique et l'utilisation des tableaux. Les « facilités » d'Ada (comme l'affectation de partie de tableaux par exemple) sont présentées à la fin des cours, après leur écriture « pour de vrai ». Dès le troisième semestre on commence l'introduction au module avec le développement de plusieurs corps d'un module sur les listes (ou autres). Enfin un projet dans lequel (cela dépend des années) les groupes se réunissent ET définissent les spécifications (.ads) de tous les modules. Ils doivent ensuite respecter ces spécifications pour pouvoir inter-changer des parties du projet. 

Des avantages du langage Ada, pour l'enseignement en DEUG, citons :
- une sémantique très sérieuse,
- une égalité des étudiants au départ face aux connaissances antérieures (en effet, certains arrivent en connaissant le C, par exemple),
- des concepts de haut niveau faciles pour une sensibilisation au génie logiciel,
- l'accent sur le typage et la vérification de type pour l'apprentissage de la rigueur.
Côté inconvénients citons .... le manque de personnels compétents (vacataires, .....) !

Dans l'enseignement en DEUG de nombreux enseignements informatiques se font encore avec Pascal (qui reste, certes, un bon outil pédagogique) mais il y aurait tout à gagner à monter d'un cran encore ces avantages avec la transition vers Ada, sans compter qu'il existe un traducteur Pascal vers Ada (voir plus loin) qui peut faciliter la tâche des pédagogues. retour au plan

IUT (Bac + 2)

Le langage Ada, choisi comme premier langage d'apprentissage par exemple au département informatique de l'I.U.T. d'Aix en Provence (de 1989 à 2003) a permis de résoudre de nombreux problèmes didactiques en fédérant des enseignements modulaires, en permettant l'assimilation de concepts réputés difficiles mais incontournables au 21ième siècle  comme ceux évoqués au chapitre « les concepts bien illustrés ». 

Le thème de génie logiciel est présent dans tout le programme pédagogique de la formation IUT. L'accent mis sur la qualité est important dans la phase d'apprentissage d'un premier langage (Ada a été enseigné complètement au premier trimestre sur environ 200 heures). Si  Ada, langage réputé complexe (donc ..... difficile à enseigner  mais ceci n'est pas vrai !), est proposé, dans des formations modestes (DUT = Bac + 2) c'est que leur vocation est de former des techniciens supérieurs capables de réaliser des travaux informatiques concrets en étant rapidement opérationnels, efficaces et méthodiques. Un bon langage devrait permettre de faire assimiler, de façon concrète et élégante les concepts fondamentaux qui résisteront au moins à une décennie de professionnalisme. Beau défi pédagogique mais .....résolu avec ce langage ! Ada possède tous les avantages pédagogiques de Pascal (ce que ne permet pas le C++ mais ce dernier, très prisé dans la profession est enseigné ensuite avec Java). Les avantages pédagogiques évoqués sont alliés, avec Ada, avec la rigueur et le professionnalisme des langages dédiés au génie logiciel. Le meilleur hommage que font les étudiants en guise de bilan peut se résumer dans ces propos :« Au début, j'ai été très irrité par le compilateur Ada qui ne laissait rien passer, mais, à la fin, quand mes programmes Ada, assez conséquents, tournaient du premier coup j'ai compris que le compilateur était plutôt mon ami ! ».

Notons tout de même un petit bémol quant aux stages de nos étudiants. Le stage de fin d'études I.U.T. étant très court (10 semaines) il est rare d'en trouver en Ada plutôt proposé sur 5 mois (donc destinés aux ingénieurs!). retour au plan

Bac + 4

A l'IUP informatique de Brest le langage Ada 95 propose une approche temps réel complète et intéressante dans un contexte d'enseignement. Elle permet de voir comment un langage et ses constructions peut offrir les services et fonctions que traditionnellement le programmeur invoque par des appels de bas niveau (librairie de threads par exemple). La présentation du modèle de tâches Ada est suivie de celle de l'annexe temps réel ce qui permet d'aborder les thèmes avancés du temps réel (ordonnancement, inversion de priorité, par exemple). Des TPs permettent ensuite d'appliquer les concepts vus en cours.

En licence d'informatique à Limoges Ada est utilisé comme support du cours sur la réutilisation. L'argumentaire est que les autres langages ne fournissent pas un outillage de puissance et de souplesse suffisantes pour la mise en oeuvre des concepts sans une excessive technicité de langage. Il est à noter que la réutilisation est vue pour elle même indépendamment du concept d'objet dans la mesure où l'on peut faire des objets sans réutilisation et de la réutilisation d'autre chose que des objets. retour au plan

Ingénieurs et BAC + 5

Ada est enseigné à Télécom Paris depuis presque la création du langage. Actuellement, Ada 95 nous permet de montrer à des étudiants de deuxième et troisième années (80 élèves) les différences d'approche entre la programmation structurée et celle orientée objet. Par ailleurs, le langage sert de support à des cours de programmation concurrente et de systèmes temps réel (travaux pratiques sur un serveur sporadique notamment). De  nombreux projets d'étudiants et de stages de DEA ont été développés en Ada 95. Les vertus du langage ont permis d'intégrer très facilement ces contributions dans des projets désormais bien connus comme GLADE, AdaBroker, PolyORB, autant de logiciels libres développés à l'ENST. Pour terminer, il faut signaler que dans le cadre d'une collaboration ENST (L. Pautet) - LIP6 (F. Kordon), plusieurs thèses se sont déroulées ou se déroulent sur des thématiques d'intergiciels génériques et temps réel, ceux-ci étant développés en Ada 95. En conclusion, l'enseignement d'Ada 95 à l'ENST rencontre un franc succès, les étudiants s'étant intéressés à ce langage contribuant par la suite activement à la promotion d'Ada 95.

A l'Ensieta Brest (http://www.ensieta.fr/). Le programme est très similaire à celui proposé à l'IUP informatique de Brest mais avec une approche systèmes embarqués. Cet enseignement permet d'aborder ainsi la complémentarité des thèmes temps réel et embarqués.

A l'ENST Bretagne nous présentons l'annexe distribution d'Ada 95 ainsi que les modèles de programmation associés. Ce cours donne un aperçu de la programmation distribuée avec une approche langage et montre comment l'annexe est implantée dans l'environnement GNAT. retour au plan

Professionnels

    Ada étant utilisé dans nombre de projets de grande importance, il y a une demande de la part des industriels pour des formations continues d'introduction au langage. Ces formations ont des contraintes différentes du milieu universitaire
- Elles doivent être courtes (le fait qu'un ingénieur soit indisponible coûte plus cher que la formation elle-même). Par exemple, chez Adalog la formation complète dure 6 jours. Chez Aonix, elle est fractionnée en deux cours (élémentaire et avancé) de 5 jours chacun.
- Les stagiaires ont, a priori, des connaissances générales de programmation.
- Les industriels veulent que les stagiaires soient directement opérationnels en sortie de formation.
    Dans ces conditions, le risque est grand de focaliser le cours sur les aspects syntaxiques ou simplement directement pratiques, en évitant les aspects philosophiques. Bien sûr, les cours dispensés par des entreprises spécialisées en Ada évitent cet écueil, mais il existe des organismes de formation qui ajoutent Ada à leur catalogue sans réelles connaissances du domaine. Adalog a ainsi reçu une fois un groupe de stagiaires qui avaient suivi une formation dans un de ces organismes, et qui, percevant un manque, étaient revenus faire un deuxième stage. Réflexion d'un stagiaire à la fin de la formation: « c'est incroyable, ce n'est pas le même langage ! »
    En plus des développeurs, de nombreux stagiaires sont des responsables qualité ou des responsables chargés de recevoir du code développé par des sous-traitants. Leur particularité est qu'ils doivent essentiellement lire du code plutôt que de l'écrire. Ce sont généralement les plus enthousiastes, car les fonctionnalités du langage correspondent très bien à leurs préoccupations. retour au plan

CNAM

Le Cnam utilise le langage Ada pour :

-- l'apprentissage de la programmation et comme support algorithmique :
        
  en premier cycle dans l'UV "Algorithmique et Programmation A " (APA),  dans l'UV "Structures de Données" (où une comparaison est faite entre les langages Ada, Java et C++) ainsi que dans une valeur de projets
        
• en second cycle dans l'UV "Accueil et Reconversion à l'Informatique" (VARI) où une synthèse des cours APA et Structures de Données est faite pour des élèves souhaitant se convertir à l'informatique (à partir de Bac + 2)

--  l'apprentissage des mécanismes de synchronisation présents dans les systèmes au second cycle dans la valeur Système Informatique (SIB)

--  l'étude de la programmation concurrente en fin de second cycle dans la valeur  "Applications Concurrentes, Conception et Outils de Validation" (ACCOV) où les solutions Ada sont comparées aux solutions Java ou Posix

-- une initiation à la programmation des systèmes temps réel en fin de second cycle dans la valeur "Systèmes Temps Réels" ou en troisième cycle dans la valeur "Micro Informatique"

Toutes ces unités de valeur sont également enseignées dans les centres régionaux du réseau Cnam.  retour au plan

Suisse (Bac + 3)

Les HES (Hautes Ecoles Spécialisées) comprenant les Écoles d’ingénieurs comme l’EIG (Ecole d’ingénieurs de Genève), l’EIVD (École d’ingénieurs du canton de Vaud) ou encore l’EIAJ (école d’ingénieurs de l’arc jurassien) dispensent un enseignement de niveau universitaire sur trois ans et trois mois (travail de diplôme à plein temps). L’introduction d’un Mastère est prévue à court terme, en relation avec le modèle de Bologne.

A l’EIVD, Ada constitue la brique de base de la formation en analyse et programmation, et fournit le (ou un) langage d’application dans des matières comme algorithmes et structures de données, programmation concurrente et temps réel ou encore génie logiciel. D’autres langages viennent ensuite se greffer sur les concepts abordés d’abord en Ada. A la fin de leur cursus, les étudiants de la filière d’informatique orientation logiciel auront étudié et pratiqué Ada pendant 600 heures environ, ceux de la filière d’informatique technique environ 200 heures. Soulignons cependant qu’Ada est enseigné comme premier langage à tous les étudiants de première année (environ 180 personnes) du département E+I qui comprend la formation non seulement en informatique, mais aussi en génie électrique, en électronique et en télécommunications. Ce choix pédagogique est accepté dans le département encore aujourd’hui, même si les pressions de tous ordres pour l’utilisation d’un autre langage existent bien évidemment !

A l’EIG, l’approche générale est analogue à celle de l’EIVD. Ada est enseigné dans deux filières: informatique et télécommunications. Tout comme à l’EIVD, le langage est utilisé pour divers enseignements : algorithmique et programmation, machines abstraites, programmation concurrente et temps réel et génie logiciel (env. 600 heures pour la filière informatique et 380 pour la filière télécommunications). A relever l’utilisation dans le cours de systèmes réactifs d’environnements tels que Statemate MAGNUM, SCADE ou encore Rhapsody in Ada (UML), lesquels permettent de générer du code source Ada.

La formation Ada est également appréciée par nos collègues des systèmes numériques qui enseignent notamment le langage VHDL (description comportementale du matériel). La similitude de ces deux formalismes leur permet d’optimiser leur enseignement.

Particularisme de l'EIG, cette dernière abrite également sur son site une EET (Ecole d'enseignement technique) qui prépare, en trois ans, ses étudiants à l'obtention de la maturité technique et à l'entrée à l'EIG. Historiquement, elle était intégrée dans le cursus des études d'ingénieur. Ce qui explique pourquoi un enseignement Ada y est toujours dispensé. Cet aspect est intéressant à plus d'un titre. Il prouve si besoin était, qu'un enseignement de l'algorithmique et de la programmation en Ada 95 serait judicieux dans les gymnases et les lycées.

retour au plan

Retour page perso D. Feneuille

Retour site Ada France

Les aides et les outils

Les compilateurs

    Les compilateurs ont tous la propriété de respecter la norme (tests de validation obligatoires). Pour évidente qu'elle paraisse cette remarque n'est pas toujours valable avec les langages concurrents ! Ada est implémenté sur pratiquement tous les environnements et tous les systèmes. Citons :

    Contrairement aux rumeurs, Ada n'est ni trop lent ni ne génère du code volumineux. Gnat (par exemple) utilise les mêmes environnements que les autres langages du GNU Compiler Collection, communément appelé GCC. Il existe aussi des directives pour obtenir l'effet souhaité (l’option –largs -s par exemple). On notera aussi comme curiosité que les 3/4 du compilateur GNAT est écrit en ... Ada ! retour au plan

Les environnements de développement (I.D.E.)

Les I.D.E. permettant de développer en Ada sont nombreux et ... de qualité. Les gratuits ont ici notre préférence

Le graphisme et Ada

GtkAda est une bibliothèque de composants graphiques permettant de créer des interfaces utilisateur et de faire du dessin.
GtkAda est un logiciel libre, fondé sur Gtk+, et disponible sur la plupart des plate-formes. La page principale est en 
http://libre.act-europe.fr/GtkAda

Cette bibliothèque permet de faire aussi bien de simples applications que des interfaces très évoluées, comme par exemple GPS, un environnement de développement écrit en Ada: http://libre.act-europe.fr/gps (voir plus haut rubrique I.D.E.)

GtkAda peut aussi être utilisé avec un générateur d'interfaces ("GUI builder") appelé "Glade", à ne pas confondre avec l'autre Glade, qui permet de faire du développement d'interfaces distribuées en Ada. retour au plan

Internet et Ada

AWS est un serveur Web, sous forme de bibliothèques, que l'on peut embarquer dans toute application Ada. Ceci permet à l'application de communiquer avec l'extérieur en utilisant le protocole HTTP. Une utilisation courante d'AWS est d'embarquer l'interface graphique de l'application sous forme de pages Web. L'utilisateur peut alors piloter ou récupérer les données de l'application en utilisant un simple navigateur Web. Outre le protocole HTTP, AWS gère aussi HTTPS (HTTP sécurisé), LDAP, SMTP, SOAP, WSDL, ... En une dizaine de lignes de code, AWS sait aussi devenir un simple serveur de pages Web.

La version A.W.S. 1.3 (dernière version distribuée lors de l'écriture de ce document) a été utilisée dans de nombreux projets et dans différentes entreprises. Bien que, lorsque l'on parle de serveur Web, on entend Apache (incontestable leader sur le marché), AWS par son approche « embarquée » a déjà séduit un ensemble d'utilisateurs. Il est aussi intéressant de mentionner que cela permet de faire une application "classique" dont l'interface utilisateur est réalisée par un browser. Exemple: un pilote de processus (ou d'expérience scientifique) que l'on peut contrôler à distance.

S'il est incontestable que Ada est, dans la plupart des esprits, associé au temps réel et aux codes à haute criticité, on voit que AWS est un bon exemple prouvant (si cela était nécessaire) qu'Ada est aussi bien adapté au monde des systèmes d'information. retour au plan

Les Bases de Données et Ada

Voir le projet GNADE  (à voir en priorité) puis sur le site Ada France :
http://www.ada-france.org/article21.html .
Si GNADE est la référence pour l'embedded SQL, il y a aussi des interfaces directes, notamment via ODBC. retour au plan

Méthodes et Ada

    Le choix d'une méthode part, à peu près, du même constat que pour les langages. En ce qui nous concerne ici, une fois le choix d'Ada fait, le développeur qui cherche ce qui le guidera vers une application bien conçue se retrouve à choisir entre du sérieux ou du tentant

    Le tentant c'est ce qui est en vogue. En effet, en faisant ce que fait tout le monde on risque moins d'être vu comme un « extra terrestre » et moins critiqué si l'on a des difficultés. Dans ce cas le choix actuel c'est UML, langage supporté par un rouleau compresseur médiatique (l'université étant loin, d'ailleurs, d'y être étrangère car la course aux publications pousse à s'intéresser au plus récent). Si nous avons qualifié UML de langage et non de méthode c'est qu'UML ne véhicule pas de démarche à proprement parler. Il faut donc que chacun trouve sa propre démarche pour la formaliser grâce à la notation qui, elle, est formalisée.

     Le sérieux (sous ce vocable nous entendons par là : éprouvé, solide, et efficace) c'est HOOD :

éprouvé : car l'industrie aérospatiale a développé suffisamment d'applications de grande envergure avec cette méthode pour que l'on ait un retour d'expérience conséquent (Ariane, Colombus, Eurocopter et bien d'autres),
solide : car ce retour d'expérience a démontré la qualité induite par la méthode et la robustesse du logiciel en découlant,
efficace : parce que terriblement bien inscrite dans le cycle de vie du logiciel. Méthode idéale pour le partage industriel (la démarche
« top down », qui formalise les interfaces avant partage, a prouvé son efficacité) elle est, à l'autre bout de la chaîne idéale pour la maintenance du code. En effet la qualité de la génération de code (facilitée par la parfaite bijection entre les concepts HOOD et les concepts Ada) permet (chose rare) de pouvoir non seulement produire mais aussi maintenir le code à travers l'outil de conception. Et encore cette totale adéquation est-elle très sous-employée (qui a utilisé de façon opérationnelle le concept de noeuds virtuels de HOOD qui permet la seule vraie répartition re-configurable ?).

     On peut, pour essayer de gagner sur (presque) tous les tableaux, faire du HOOD en notation UML. Si l'on concilie ainsi la rigueur et la « persuasion », on en perd un peu les facilités de génération de code Ada (puisque on fera ça avec des outils UML et non pas des outils HOOD).  

    Le débat entre courant principal et courant d'excellence est difficile à mener dans l'industrie car il faut souvent plus convaincre politiquement que techniquement. Dans l'enseignement cette question devrait être moins cruciale et il est de la responsabilité des enseignants de donner aux étudiants toutes les armes pour choisir en toute connaissance de cause. Ils seront bien, assez tôt amenés, à choisir en prenant en compte ces contraintes politiques.  Un étudiant capable de comprendre une spécification exprimée en UML (sans rivale à ce niveau), de concevoir en HOOD le logiciel qui répondra à ces spécifications et de générer l'application Ada (avec, par exemple,  une répartition re-configurable grâce à l'annexe Ada 95) sera bien armé pour aborder sa première application industrielle. retour au plan

Des bibliothèques

Les bibliothèques Ada sont nombreuses et variées.

Le site d'Ada France propose (et tient à jour) de nombreuses bibliothèques, logiciels et outils de développement on verra donc en premier tous les pointeurs proposés. Ajoutons  (liste à compléter !) :
Carbon-Ada : disponible sur www.MacAda.org (en anglais) qui comme on peut le deviner permet de marier un langage de qualité avec un système  qui ne l'est pas moins !
Nacelles Pointées : disponibles sur http://ballons.cnes.fr/nacelles_pointees logiciels développés au CNES (testés sur Linux et Windows). retour au plan

Interfaçage avec d'autres langages

    Ada (et cela peut surprendre) permet, souvent, de faire ce qui est réalisable dans un langage de bas niveau comme le C (on va en voir un exemple). Par contre, le compilateur Ada (pour faire du bas niveau) obligera le programmeur à préciser explicitement les opérations dangereuses (du genre Unchecked). En C le mode dangereux est le mode par défaut totalement antinomique avec Ada qui demande beaucoup plus d'efforts (prix à payer pour du code plus fiable).

    Cependant, Ada permet d'utiliser des composants écrits dans d'autres langages : C, Fortran ou Cobol (et même dans les deux sens) grâce à des paquetages (fils de Interfaces) et des pragmas (directive pour le compilateur) assez simples à mettre en oeuvre.
    Pour interfacer Ada avec un autre langage (normalisé !) il faut que Ada manipule des types qui soient « homogènes » avec leur équivalent dans l’autre langage. Par exemple pour interfacer le C on dispose en Ada du paquetage Interfaces.C qui déclare de nouveaux types Ada mais possédant une structure compatible avec les types équivalents en C. En effet si en C l'implémentation des types prédéfinis est précisée par la norme en Ada l'implémentation est laissée au compilateur.  Pour en savoir plus.

    On notera donc que si certains modules écrits en C sont intéressants Ada peut les intégrer. Mais C n'est pas incontournable pour accéder au bas niveau car rien n'empêche de programmer, en Ada, des applications de bas niveau. A titre d'exemple on peut consulter un petit bout de code Ada permettant de travailler au niveau du bit (sans masque et autre xor) mais surtout en gardant une vision de haut niveau. Ce bout de code montre une manipulation que le C est incapable de réaliser sans un masque xor, démarche peu lisible et sujette à erreur d'interprétation notamment lors d'une maintenance. Dans cet exemple (comme dans d'autres), Ada est mieux adapté à la programmation de bas niveau que le C. 

On peut aussi citer les interfaçages avec Tcl/TK, Python, Java, C#, et Lua retour au plan

Traducteurs avec d'autres langages

Acceptent en entrée du codage en C, Pascal ou Fortran pour produire en sortie du code Ada

Livres, cours, didacticiel

retour au plan

Retour page perso D. Feneuille

Retour site Ada France

Des adresses d'établissements

Voilà un chapitre présentant des formations qui pourrait demander du temps si l'on souhaite être exhaustif !

L'École d'ingénieurs du canton de Vaud en Suisse (EIVD)
Toujours en Suisse l'EIAJ (Jura) et EIG (Genève)
L'INSA de Toulouse
Sup Aéro Toulouse et aussi l’ENICA
L'université Paul Sabatier de Toulouse Licence, I.U.P., DESS
L'ENSIMAG à Grenoble
L'ENSMA à Poitiers
l'UTBM à Belfort
Paris 12 icence et MIAGE à Créteil
DEUG MIAS à Évreux
Paris 6 Licence
CUST à Clermont Ferrand et Licence
l'INP à Grenoble (télécommunication)
l'ENST à Paris et DEA
Licence à Limoges
l'ENS (ULM)
Paris Sud DEA
IUT Valence, Grenoble, Aix, Orsay, ...
CNAM (certainement le plus gros contingent avec tous les centres associés de province)
Orsay FIIFO (ingénieurs en alternance)
l'ENAC à Toulouse
IUP GMI Lille
MIAGE Lille
UQAM Montréal Québec

Une liste (mais avec des adresses complètes) est disponible sur le site d'Ada France

retour au plan

Retour page perso D. Feneuille

Retour site Ada France

Conclusion

    Arrivé à ce stade, le lecteur (convaincu de l'intérêt d'Ada ?) se posera certainement quelques questions : 

Pourquoi Ada n'est-il pas plus répandu
?

    On pensait, au début (vers 1980), que Ada remplacerait rapidement les langages alors principalement utilisés : Fortran, Pascal et, dans une moindre mesure, Cobol. Or si le langage Ada s'est bien introduit dans les domaines sensibles (aéronautique, aviation, domaine militaire, nucléaire, contrôle de processus), sa diffusion est restée modeste dans les domaines de la programmation dite traditionnelle : scientifique, gestion, programmation système, alors qu'on assistait à une montée en force du langage C, et plus tard (depuis 1990) de C++ et maintenant et récemment Java (sans parler des langages de script).
    Pourtant, toutes les mesures effectuées sur des projets réels ont montré que les bénéfices que l'on pouvait espérer d'Ada étaient obtenus ou dépassés : meilleure qualité de la conception, réutilisation, augmentation de la productivité des programmeurs, infléchissement de la courbe des coûts en fonction de la taille des logiciels, effondrement du taux d'erreurs résiduelles et des coûts d'intégration, efficacité du code produit ; et ceci, quel que soit le domaine d'application concerné
    Mais le choix d'un langage de programmation fait intervenir de nombreux éléments, qui touchent plus à la psychologie qu'à l'économie.
    Tout d'abord, l'expansion de C est liée au développement du système UNIX. Il est de tradition de fournir gratuitement le compilateur C avec les outils standard d'UNIX . Pourquoi alors acquérir un autre langage ? D'autant plus que C a pour lui une extrême simplicité (d'aucuns disent même pauvreté) de concepts. Remarquons au passage que ces arguments ne s'appliquent plus à C++ : des compilateurs sont payants , et le langage est devenu bien plus compliqué !
    Historiquement, UNIX a été développé par un petit nombre d'individus, sans souci de politique d'ouverture commerciale. Les interfaces ont donc été pensées uniquement en fonction des particularités du C ; c'est ainsi qu'une fonction peut retourner par exemple soit un pointeur, soit la valeur False (c'est à dire en fait zéro, qui est également le pointeur nul !). De telles violations de typage sont incompatibles avec la plupart des langages évolués, mais fréquentes avec C. Il en résulte des difficultés à faire des interfaces abstraites, propres, pour beaucoup de fonctionnalités UNIX, ce qui accentue le retard, en particulier au niveau de la standardisation, des autres langages par rapport à C. Et puis la « sagesse populaire » affirme que l'on doit programmer en C sous UNIX, sans plus d'explication.
    En dehors de ces considérations pratiques, l'attirance du programmeur moyen pour C, et la peur instinctive qu'il éprouve vis à vis d'Ada, plongent leurs racines bien plus profondément. Beaucoup de programmeurs encore peut être en fonction ont été formés à une époque où l'assembleur était roi. Nous avons connu des centres de calcul où les « nobles » (ceux qui étaient capables d'écrire tous leurs programmes en langage machine) regardaient de haut les novices qui n'étaient bons qu'à programmer en Fortran. Avec le temps, la programmation en assembleur tend à disparaître, car les problèmes de fiabilité, de maintenabilité et de portabilité sont vraiment devenus trop importants. Que sont devenus ces programmeurs  ? Eh bien ils ont fait et font sûrement encore du C. Ils ont trouvé un langage qui n'est en fait, selon la définition de ses auteurs, qu'un assembleur portable. Comme nous l'avons vu, il permet de faire (presque) tout ce que l'on pouvait faire en langage machine et n'implique aucune remise en cause ni des méthodes ni de la façon de programmer. Inversement, Ada a été spécifiquement conçu pour obliger les programmeurs à modifier leurs habitudes ! En particulier, la programmation Ada s'accompagne d'une description plus abstraite des traitements. Outre que ceci nécessite un effort de réflexion plus important, le programmeur tend à perdre le contact direct avec la machine. Il doit faire confiance au compilateur pour la génération de code efficace, et ne doit plus se préoccuper du parcours exact du programme. Il n'est guère étonnant que l'inertie naturelle ne rende pas Ada très attrayant a priori au programmeur qui n'a pas saisi (car il n'a jamais essayé) les bénéfices d'une approche de plus haut niveau.  Mais bien sûr, l'attirance naturelle du programmeur ne saurait être un critère pour un choix technologique dont dépendra tout le projet ! De façon plus imagée :
C++ ressemble à un énorme gâteau à la crème, ruisselant de sucreries ; Ada ressemble plus à un poisson poché /pommes vapeur. Les questions intéressantes sont :
1) quel est le meilleur pour votre santé
2) qu'est ce que les gens ont tendance à choisir spontanément ?
   
Les compilateurs Ada ont eu aussi mauvaise réputation. Les premières années (vers 1985), l'effort des fabricants s'est plus porté sur la conformité à la norme, vérifiée par l'incontournable suite de validations, que sur l'efficacité pour laquelle il n'y avait aucune obligation légale. Des compilateurs sont maintenant disponibles sur quasiment toutes les machines du marché, et des mesures objectives ont montré qu'ils étaient au moins aussi performants et fiables que les compilateurs C. Il n'en reste pas moins que le langage continue à traîner quelques vieilles « casseroles », d'autant qu'il est difficile de supprimer de la littérature les comptes rendus des premières expériences.

Un langage ne peut se répandre que s'il est enseigné.

   
Force est de reconnaître qu'Ada n'a pas réussi à séduire tous les universitaires. A cela au moins trois raisons.
    Au début (1985) le prix des compilateurs, justifié en milieu industriel par le gain de productivité apporté, a été un obstacle certain. C'est ce qui a conduit le DOD, plus tard, à financer GNAT, pour mettre à la disposition de tous un compilateur Ada 95 gratuit.
    En dehors du coût, chercheurs et enseignants ont, aussi, généralement, des contraintes différentes des industriels : leurs logiciels n'ont que rarement à être maintenus, et doivent, souvent, être développés très rapidement. Même si leurs cours d’informatique prônent le génie logiciel et l'importance de favoriser la maintenance au détriment de la facilité de développement, les universitaires appliquent rarement ces bons principes à eux mêmes ! Inversement, les langages orientés objet sont à la mode et semblent offrir des facilités supplémentaires (mais cet argument n'a plus lieu d'être avec Ada 95 qui les propose aussi).
    Enfin, le fait que le DOD ait financé le développement d'Ada lui a créé, sûrement, une certaine antipathie dans les milieux universitaires, traditionnellement antimilitaristes.

Paradoxalement, les promoteurs du langage ont pu lui faire du tort par excès de purisme en exigeant de faire du 100% Ada.

   
Le langage a tout prévu pour permettre d'écrire des modules en d'autres langages (C, Fortran, Cobol) si c'était plus commode ; il autorise même l'écriture de modules en assembleur. Si ces éléments sont alors non portables, ce n'est pas trop grave dans la mesure où le mécanisme d'empaquetage garantit que ces non portabilités sont répertoriées, aisément identifiées, et sans effet sur les utilisateurs des paquetages. Il n'y a donc pas de honte à écrire un corps de module en assembleur ou en C si, par exemple, il n'y a pas d'autre moyen d'obtenir les performances requises. En exigeant le « tout Ada » au delà du raisonnable, on risque de se heurter à des problèmes tout à fait localisés, mais dont la publicité risque de discréditer le langage tout entier.

Enfin, il est remarquable de constater que les plus virulents adversaires d'Ada ... ne l'ont jamais vraiment pratiqué !

   
Peut être ont ils juste fait quelques essais, sans formation appropriée, en traduisant « littéralement » des bouts de code d'autres langages avec lesquels ils étaient familiers. Au bout de quelques erreurs de compilation, ils ont décidé que le langage était difficile, et n'ont pas poursuivi. Inversement, ce n'est qu'à l'usage que l'on en apprécie tous les avantages : typage fort, exceptions, parallélisme, paquetages hiérarchiques, etc. Il est certain que pour tirer tout le bénéfice d'Ada, il ne suffit pas d'apprendre la syntaxe ; il faut assimiler l'état d'esprit, c’est à dire « la façon de faire » qui va avec. Il faut admettre qu'un langage comme Ada joue un rôle différent dans le processus du développement du logiciel et que, comme on l’a vu, le choix du langage de codage n'est pas neutre : précisément parce qu'il peut être beaucoup plus qu'un simple outil de codage. Comme le remarquait G. Booch en 1991 : « Donnez une perceuse électrique à un charpentier qui n'a jamais entendu parler de l'électricité, et il l'utilisera comme marteau. Il tordra des clous et se tapera sur les doigts, car une perceuse fait un très mauvais marteau ».

Si les mauvaises nouvelles courent vite, il est plus difficile de répandre les bonnes.

   
Ada n'a pas toujours su « faire sa pub ». Qui, en dehors des convaincus, sait qu'Ada a été utilisé (il y a longtemps et avec succès) dans de nombreux programmes de gestion, dont un projet de 2,5 millions de lignes de code qui a pu être développé avec la moitié du coût initialement prévu  Qu'un logiciel qui n'arrivait pas à tenir ses contraintes temps réel a été réécrit en Ada avec des performances satisfaisantes. Qu'une entreprise gère plusieurs projets totalisant un million de lignes de code en n'employant qu'une seule personne à la maintenance.
    Soyons honnête cependant : au début les utilisateurs d'Ada 83 ont pu rencontrer des difficultés objectives, même si la plupart ont appris à « vivre avec ». On notait en particulier le manque de support des méthodes par classification, de trop nombreuses re-compilations dans les grands projets, des difficultés d'interfaçage avec d'autres langages ou des bibliothèques... et le manque de fiabilité des premiers compilateurs et des environnements de programmation, la prolifération des tâches pour de simples synchronisations (car il n’y avait qu’un concept de synchronisation, le rendez-vous). Ces problèmes ont disparu depuis plus de dix ans, ou, ont été résolus par Ada 95 et peuvent être maintenant considérés comme sans objet par exemple grâce à l’excellent choix de l’objet protégé dans les synchronisations. Il faut, quand c’est possible, abandonner le rendez-vous pour traiter la synchronisation et ne le garder que pour les appels conditionnels ou temporisés ou pour initialiser des données propres à une tâche (autrement dit, on utilise le rendez-vous quand on ne peut pas traiter le problème avec un objet protégé).

Une petite devinette pour finir :        « Ada, C, +, for, requeue, to, at ! »        Solution ?

retour au plan

Retour page perso D. Feneuille

Retour site Ada France


Annexes (des exemples et des compléments)

    On verra dans cette dernière partie quelques exemples (ou certains développements) illustrant plus finement les arguments développés dans le texte principal. Ces lignes ne sont pas fondamentales pour la compréhension des argumentations mais devraient permettre de mieux les valider.

Un exemple de typage

type T_Température is range -20..55; 
créé un famille d'objets numériques entiers dont les valeurs sont contraintes entre les bornes -20 et 55. Ada est fortement typé ce qui interdit de façon implicite les mélanges (accidentels ou voulus). Ainsi :

Valeur : Integer;       -- instanciation d'un entier prédéfini
Temp   : T_Température; -- instanciation d'un objet de type déclaré

Temp := Valeur; -- erreur
Temp := -25;    -- erreur

Les deux instructions ci dessus sont rejetées par le compilateur. Des conversions sont possibles, elles ne sont pas implicites et doivent être précisées.

Temp := T_Température (Valeur); -- conversion

est une instruction correcte syntaxiquement. Mais, à l'exécution, une valeur hors de l'intervalle lèvera une exception.

retour à l'appel

Travail au niveau du bit

    Le langage C est « proche » de l'implémentation machine ; trop d'ailleurs, comme on l'a vu, si l'on se place dans le domaine du génie logiciel. Malgré cela il est mal commode, en C, de travailler directement au niveau du bit. Il faut en passer par des opérations (masques, xor, etc.) qui font perdre une représentation de haut niveau et nuisent à la lisibilité. Voici un morceau de code Ada permettant de travailler élégamment au niveau du bit tout en gardant un haut niveau d'abstraction. On remarquera l'utilisation de directives spécifiant au compilateur des implémentations particulières (for ... use). En gras les mots réservés du langage.

type T_Couleur is (Noir, Bleu, Vert, Cyan, Rouge, Magenta, Marron, Gris, Gris_Sombre,
     Bleu_Clair, Vert_Clair, Cyan_Clair, Rouge_Clair, Magenta_Clair, Jaune, Blanc);
for T_Couleur use (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);

subtype T_Couleur_Fond is T_Couleur range Noir .. Gris;

type T_Clignotement is (Fixe, Clignotant);
for T_Clignotement use (0, 1); -- on force ainsi l'implémentation

type T_Curseur is record -- déclaration des propriétés d'un curseur
    Aspect  : T_Clignotement;
    Arrière : T_Couleur_Fond;
    Devant  : T_Couleur;
end record;
for T_Curseur use record  -- on impose un octet (bits 0 à 7)
    Aspect  at 0 range 0..0; -- bit 0
    Arrière at 0 range 1..3; -- bits 1 à 3 
    Devant  at 0 range 4..7; -- bits 4 à 7
end record;

    Une instruction du style : Mon_Curseur.Aspect := Fixe; permet de modifier directement le bit n° 0 de l'octet avec l'effet voulu. Ainsi que : Mon_Curseur.Aspect := Clignotement; On travaille ainsi directement sur le bit à l'insu de son plein gré !

retour à l'appel

Compléments interfaçage avec C.

    L'interfaçage Ada avec C oblige le programmeur Ada à utiliser des nouveaux types mais compatibles C. Par exemple : int, short, long sont trois identificateurs de nouveaux types entiers Ada « compatibles » C. Le lecteur qui connaît les identificateurs des 3 types primitifs C équivalents constatent que les 3 identificateurs Ada ont été choisis identiques, en effet, ces identificateurs n’existent pas en Ada (ce sont Integer, Short_Integer et Long_Integer). C’est une bonne idée « mnémonique » ! Pour les types réels en virgule flottante on trouve C_float, double, long_double. Dans cet exemple le premier identificateur ne peut prendre son label C habituel : float pour éviter une confusion avec le type prédéfini Ada Float de même identificateur. Il sera donc nommé C_float. Les deux autres sont identiques à leur homologue C (car en Ada pas de confusion : Long_Float et Long_Long_Float). On notera aussi char et char_array. Respectivement char pour définir des « sortes » de Character et char_array pour définir des tableaux de caractères (String) ; char n’existant pas en Ada est utilisé. On notera aussi dans la bibliothèque (paquetage Interfaces.C) les fonctions To_C et To_Ada (respectivement) qui permettent de convertir des types prédéfinis Ada en leur équivalent Ada compatibles C ou les types Ada compatibles C en types prédéfinis Ada (respectivement).

Un exemple : déclaration d'un procédure Ada réalisée en C (puis utilisation)  :

procedure C_System (Chaine : in Char_Array);
pragma Import (C, C_System, ”system”);

     La procédure Ada C_System est réalisée avec le sous programme C connu system grâce au pragma Import. Ainsi l'instruction Ada : C_System(To_C("ls -l")); permet d'afficher en Ada le répertoire courant Linux. La chaîne de caractères String Ada "ls -l" est convertie (grâce à To_C) en char_array chaîne compatible C et devient paramètre de system qui se substitue à C_System.
    Notons cependant que cette technique n'est pas celle que l'on utilise traditionnellement en Ada pour lancer une commande, en effet, un bibliothèque existe pour cela. Mais l'exemple est assez concis et significatif pour la compréhension de l'interfaçage (nous semble-t-il !).

retour à l'appel

Exemples de lisibilité

Ada est plutôt réputé verbeux (moins que Cobol tout de même !) mais c'est une qualité quand cette verbosité permet de relire facilement du code ou le faire partager. Voici deux exemples l'un très simple le deuxième un peu plus compliqué.

Premier exemple : comparons : une instruction Ada (en  première ligne) puis son équivalent en C (deuxième ligne).

Vect(5..7) := Vect(10..12); -- affectation d'une tranche de tableau
memcpy (vect+5,vect+10,3*sizeof(*vect));

Quelle instruction est la plus lisible ? On remarque sur la deuxième ligne (mais c'est bien connu) que le développeur C est très préoccupé par la représentation mémoire alors qu'en Ada c'est le compilateur qui fera l'implémentation, à son idée, sans intervention du programmeur. Voir aussi plus haut l'exemple permettant de travailler au niveau du bit en Ada où l'instruction Mon_Curseur.Aspect := Fixe; est fort lisible et dit significativement ce qu'elle fait !

Deuxième exemple : écriture d'un sous programme (Ada puis C) qui place les quatre derniers caractères d'une chaîne en tête.

procedure Swap (Str : in out String) is
begin
  
if Str'length < 4 then return; end if; -- contrôle validité
   Str := Str (Str'Last-3 .. Str'Last) & Str (Str'First .. Str'Last-4);
end Swap;

void
swap (char *str)
{
int len = strlen (str);
char *tmp;

if (len < 4) return;
tmp = (char *) malloc (len + 1);
strncpy (tmp, str+len-4, 4);
strncpy (tmp+4, str, len-4);
tmp[len] = '\0';

strcpy (str, tmp);
free (tmp);
}

A noter que dans ces exemples la version Ada n'utilise pas d'allocation dynamique. La construction de la nouvelle chaîne se fait sur la pile.

retour à l'appel

exemple simple de paquetage

Ce petit exemple, forcément simple, de paquetage (P_Date) sert à illustrer les deux paragraphes : encapsulation ainsi que spécifications et réalisation.

Seules les parties spec (ou contrat) seront mises en évidence, le corps (ou réalisation) n'apportant rien aux concepts à illustrer.

package P_Date is
type T_Mois is (janvier, février, mars, avril, mai, juin, juillet, 
                août, septembre, octobre, novembre, décembre);
subtype T_Numéro is Integer range 1..31;
subtype T_Année  is Integer range 1900..9999;

type T_Date is private;
procedure Saisir (La_Date : out T_Date);
procedure Editer (La_Date : in  T_Date);
fonction  Quantième (La_Date : in T_Date) return Positive;
fonction  Est_Bissextile (La_Date : in T_Date) return boolean;

................... -- ici d'autres méthodes

private
type T_Date is record
    Numéro : T_Numéro;
    Mois   : T_Mois;
    Année  : T_Année;
end record;
end P_Date;

Commentaires : le type T_Date est le T.A.D. essentiel : c'est un type article ; il est déclaré dans le paquetage P_Date qui sert d'enveloppe logicielle. Ce type est privé c'est à dire que les trois champs qui le composent sont inaccessibles par contrat. Des méthodes (non déclarées ici) pourraient permettre ces accès. Seules quatre méthodes (pour faire court) sont déclarées dans le paquetage (deux procédures d'entrée sortie et deux fonctions)..

retour à l'appel

exemple de paquetage hiérarchique

Cet exemple reprend le paquetage P_Date précédent en le complétant avec d'autres fonctionnalités dans un paquetage fils P_Date.Suite.

package P_Date.Suite is

fonction "<"  (Date1, Date2 : in T_Date) return boolean;
fonction ">"  (Date1, Date2 : in T_Date) return boolean;
fonction "<=" (Date1, Date2 : in T_Date) return boolean;
fonction ">=" (Date1, Date2 : in T_Date) return boolean;

end P_Date.Suite;

Commentaires : Comme on l'a noté dans l'exemple ci dessus le type T_Date déclaré dans le paquetage P_Date manque de fonctionnalités. Elles peuvent être déclarées plus tard en fonction des besoins des développements sans changer les premières spécifications (naturellement héritées sans dérivation). Ici nous montrons la déclaration des quatre opérateurs relationnels traditionnels. L'opérateur d'égalité n'a pas à être déclaré car il est implicite pour un type article. L'utilisation des ces opérateurs qui sont des surcharges des opérateurs prédéfinis est simple. Exemple :

Aujourd_hui, Demain : T_Date; -- instanciation de deux dates

if Aujourd_hui > Hier then .....

retour à l'appel

un exemple de classe

Cet exemple reprend le premier exemple de type abstrait de données T_Date en le déclarant (même identificateur) mais dans une enveloppe de classe le paquetage P_Date_Classe. On notera bien que en Ada le constructeur class n'existe pas !

package P_Date_Classe is
type T_Mois is (janvier, février, mars, avril, mai, juin, juillet, 
                août, septembre, octobre, novembre, décembre);
subtype T_Numéro is Integer range 1..31;
subtype T_Année is Integer range 1900..9999;

type T_Date is tagged private; -- racine de la classe
procedure Saisir (La_Date : out T_Date);
procedure Editer (La_Date : in  T_Date);
fonction Quantième (La_Date : in T_Date) return Positive;
fonction  Est_Bissextile (La_Date : in T_Date) return boolean;
................... -- ici d'autres méthodes

private
type T_Date is tagged record
    Numéro : T_Numéro;
    Mois   : T_Mois;
    Année  : T_Année;
end record;
end P_Date_Classe;

Commentaires : pratiquement aucune différence sauf le mot tagged qui transforme le T.A.D en ... classe ! Mais bien sûr c'est une autre approche où l'on postule, a priori, une extension possible de la structure de données.

Voyons maintenant le côté extension (par dérivation) de la structure de données de la classe T_Date. 

package P_Date_Classe.Suite is
type
T_Jour is (Lundi, Mardi, Mercredi, Jeudi, Vendredi, Samedi, Dimanche);

type T_Date_Complétée is new T_Date with record
     Jour : T_Jour; -- dérivation avec extension
end record;
procedure Saisir (La_Date : out T_Date_Complétée);
procedure Editer (La_Date : in  T_Date_Complétée);
fonction Ajuster (La_Date : in T_Date) return T_Date_Complétée;
................... -- ici d'autres méthodes

end P_Date_Classe.Suite;

Commentaires : la nouvelle classe étendue T_Date_Complétée se déclare toujours dans un paquetage (ici un fils). un seul champ est ajouté celui du nom du jour de la date. Deux nouvelles procédures d'entrée sortie sont déclarées (surcharge) pour la nouvelle classe ainsi qu'une fonction permettant (c'est un exemple) de rendre une date (T_Date) en son équivalente dans l'autre classe (T_Date_Complétée). La réalisation de la fonction Ajuster (faite dans le body) consiste simplement à initialiser le jour d'une date donnée.

Nous ne résistons pas au plaisir d'écrire une réalisation (qui se fait, rappelons le, dans le body !) :

procedure Saisir (La_Date : out T_Date_Complétée) is
Date_Simple : T_Date;
begin
    Saisir (Date_Simple);
    La_Date := Ajuster (Date_Simple);
end Saisir;

C'est court et ... sûr ! 
La surcharge de Saisir est parfaitement résolu par le compilateur grâce au type (T_Date) du paramètre effectif Date_Simple.

retour à l'appel

Deux exemples de programmation concurrente

         Voici maintenant deux exemples de programmation concurrente proposés par C. Kaiser. À notre connaissance, ces exemples ne sont, ni dans le manuel de référence, ni dans des ouvrages de cours. Ces exemples ont été choisis pour montrer la simplicité et la puissance de l’objet protégé. Et aussi l’utilisation qu’on peut faire des choix sémantiques pris par le langage. Si on essaie, sans précautions, de transposer ces solutions, élégantes, dans d’autres langages, comme Java, ou de les utiliser avec Posix, on va vers des catastrophes (interblocage, incohérences). Bien entendu, les solutions présentées sont transposables en Java ou en Posix, mais au prix d’une complication résultant de la programmation défensive qu’il faut mettre en œuvre.

         La documentation de ces programmes resterait à développer. Il s’agit d’abord  ici de montrer des exemples de style de programmation de concurrence avec les objets protégés. Et combien on peut avoir un plaisir esthétique en programmant la concurrence en Ada. Comme on l’a déjà dit : un vrai bonheur didactique !

UN CLASSIQUE : LE DÎNER DES PHILOSOPHES

 Version utilisant des familles d’entrées  et du « requeue ». elle est sans interblocage grâce à la sémantique de l’objet protégé (dite sémantique de l’œuf), et sans famine .

--  REPAS DES PHILOSOPHES
--  protocole interne et une baguette après l'autre

package
General is
  
N :
constant Integer := 5;
  
type Philo_Id is mod N;
end
General;
--

with General; use  General;
package
LesBaguettes is
   procedure Prendre (PourMoi : in Philo_Id);
   procedure Rendre (PourMoi : in Philo_Id);
end
LesBaguettes;

package body LesBaguettes is
  
type Tableau_De_Booleens is array (Philo_Id) of Boolean;

  
protected Baguettes is
      entry Saisir (Philo_Id); -- famille d'entrées
      procedure Restituer (X : in Philo_Id);
   private
      Disponible : Tableau_De_Booleens := (others => True);
      entry Completer (Philo_Id); -- autre famille d'entrées
   end Baguettes;

   protected body Baguettes is
      entry Saisir (for I in Philo_Id) when Disponible (I) is
      begin
         Disponible (I) := False;
         requeue Completer (I + 1);
      end Saisir;
     
entry Completer (for I in Philo_Id) when Disponible (I) is
      begin
         Disponible (I) := False;
      end Completer;
    
procedure Restituer (X : in Philo_Id) is
      begin
         Disponible (X) := True;
         Disponible (X + 1) := True;
      end Restituer;
   end Baguettes;

    procedure Prendre (PourMoi : in Philo_Id) is
   begin
      Baguettes.Saisir (PourMoi);
   end Prendre; 

   procedure Rendre (PourMoi : in Philo_Id) is
   begin
      Baguettes.Restituer (PourMoi);
   end Rendre;

end LesBaguettes;

--  *************************************************
--  voici de quoi essayer l'algorithme
--  simulation du comportement des philosophes

--  **********************************************

generic 
  
type Resultat is private; 
  
type Etat_Interne is limited private; 
  
with procedure Reset (V : in Etat_Interne); 
  
with function Prochaine_Valeur (V : Etat_Interne) return Resultat;  
package
Machine_Protegee is 
  
function Prochaine_Valeur_Protegee return Resultat;  
end
Machine_Protegee;

package body Machine_Protegee is 
  
protected Machine_Interne is 
     
procedure Reset_Interne; 
     
function Prochaine_Valeur_Interne return Resultat; 
  
private 
     
Etat : Etat_Interne; 

  
end
Machine_Interne;

   protected body Machine_Interne is 
     
function Prochaine_Valeur_Interne return Resultat is 
     
begin 
        
return Prochaine_Valeur (Etat); 
     
end Prochaine_Valeur_Interne;

      procedure Reset_Interne is 
      begin 
        
Reset (Etat); 

     
end Reset_Interne; 
  
end
Machine_Interne;

   function Prochaine_Valeur_Protegee return Resultat is 
  
begin 
     
return Machine_Interne.Prochaine_Valeur_Interne; 
  
end Prochaine_Valeur_Protegee;

begin 
  
Machine_Interne.Reset_Interne;  
end
Machine_Protegee;

--====================================

with General; use  General;  

package Scene_Philo is 
  
procedure Pense (X : in Philo_Id); 
  
procedure Mange (X : in Philo_Id);  
end
Scene_Philo;

with Ada.Text_IO, Ada.Numerics.Float_Random;  
use
  Ada.Text_IO, Ada.Numerics.Float_Random;  
with
Machine_Protegee;  
pragma
Elaborate_All (Machine_Protegee);

package body Scene_Philo is 
  
package Protected_Float_Random is new Machine_Protegee 

     (Resultat         => Float, 

     
Etat_Interne     => Ada.Numerics.Float_Random.Generator, 
     
Reset            => Ada.Numerics.Float_Random.Reset, 

     
Prochaine_Valeur => Ada.Numerics.Float_Random.Random); 
  
use
Protected_Float_Random;

   procedure Pense (X : in Philo_Id) is 
     
Duree : Float range 0.0 .. 1.0; 
  
begin  --  nouveau tirage aléatoire d'une durée 

     
Duree := Prochaine_Valeur_Protegee; 
     
Put_Line ("le philosophe " & Philo_Id'Image (X) & " pense"); 
      
delay (Duration (Duree)); -- x pense un certain temps 
     
Put_Line ("le philosophe " & Philo_Id'Image (X) & " a faim"); 
   end Pense;

  procedure Mange (X : in Philo_Id) is 
     
Duree : Float range 0.0 .. 1.0; 
  
begin --  nouveau tirage aléatoire d'une durée 

     
Duree := Prochaine_Valeur_Protegee; 
     
Put_Line ("le philosophe " & Philo_Id'Image (X) & "  mange"); 
     
delay (Duration (Duree)); -- x mange un certain temps 
     
Put_Line ("le philosophe " & Philo_Id'Image (X) & "  n'a plus faim"); 
  
end Mange;  

end
Scene_Philo;

--====================================
 
--  VOICI LE REPAS DES PHILOSOPHES  
--====================================

with General, Scene_Philo, LesBaguettes;  
use
  General, Scene_Philo;

procedure Application is 
  
package Nom is 
     
function Unique return Philo_Id; 
  
end Nom;

   package body Nom is 
     
Next_Id : Philo_Id := Philo_Id'Last;  
      -- protégé par le package 
     
function Unique return Philo_Id is 
     
begin 
        
Next_Id := Next_Id + 1; -- addition modulo N 
        
return Next_Id; 
     
end Unique; 
  
end Nom;

   task type Philo (X : Philo_Id  := Nom.Unique); 
     
Philosophes :
array (Philo_Id) of Philo;

   task body Philo is 
  
begin 
     
for I in 1 .. 65 loop 

        
Pense (X); 
        
LesBaguettes.Prendre (X); 
        
Mange (X); 
        
LesBaguettes.Rendre (X); 
     
end loop; 
  
end Philo;

begin 
  
null;  
end
Application;  

retour à l'appel

--  ========================================================  
--  UN EXEMPLE MOINS CLASSIQUE D'ALLOCATION DE RESSOURCE
--  Ce genre d'exemple nécessite de réévaluer l'état 
--  au moment du retour des ressources,
--  et de passer de l'information entre processus. 
--  En dehors de Ada, cela donne généralement
--  soit une solution compliquée 
--  soit beaucoup de réveils intempestifs de tâches 
--  Ici encore Ada permet une solution élégante.
--  Voici deux exemples, l'un très simple, l'autre compliqué 
--  comme l'est la réalité des applications concurrentes .
 
--  =============================================

--  ALLOCATEUR DE RESSOURCES : VARIANTE 1
--  allocation de ressources contrôlée par un objet protégé
--  variante 1 : la première tâche en attente 
--  bloque les nouvelles requêtes et alors
--  les nouvelles requêtes doivent attendre que 
--  la tâche en attente sur l'entrée Servir soit servie
--  Les requêtes en attente sont servies selon 
--  l'ordre de la file de Demander
--  =============================================

package Allocation1 is 
  
Max : constant Integer := 100; -- nombre de ressources
   type Des_Ressources is new Integer range -Max .. Max;
   subtype Nb_Ressources is Des_Ressources range 1 .. Des_Ressources'Last;
   type Liste_Resource is new Integer; 
   --  type à redéfinir ultérieurement
 

   protected Controleur is
      entry Demander 
            (R : out Liste_Resource; Nombre : Nb_Ressources);
      procedure Rendre 
            (R : in Liste_Resource; Nombre : Nb_Ressources);
   private
      entry Servir (R : out Liste_Resource; Nombre : Nb_Ressources);
      Disponible : Des_Ressources := Des_Ressources'Last;
   end Controleur;
end
Allocation1;

--  ===================================================

package body Allocation1 is
   protected body Controleur is 

      entry Demander (R : out Liste_Resource; Nombre : Nb_Ressources)
      when Servir'Count = 0 is
      begin
         Disponible := Disponible - Nombre; 
         if Disponible < 0 then   --  la demande doit attendre
            requeue Servir;
         else           --  la demande peut être satisfaite
            --  Fournir_Les_Ressources_Dans(R);
            null;
         end if;
      end Demander;

      entry Servir (R : out Liste_Resource; Nombre : Nb_Ressources)
      when Disponible  >=  0 is
      begin
         --  Fournir_Les_Ressources_Dans(R);
         null;
      end Servir;

      procedure Rendre 
            (R : in Liste_Resource; Nombre : Nb_Ressources) is
      begin
         --  Recuperer_Les_Ressources_De(R);
         Disponible := Disponible + Nombre;  
      
     
-- enregistre ce nombre de ressources rendues
      end Rendre;
   end Controleur;

begin
   null;
end
Allocation1;

--  =============================================
--  ALLOCATEUR DE RESSOURCES : VARIANTE 2
--  allocation de ressources contrôlée par un objet protégé
--  variante 2 : il y a un premier groupe de tâches en attente
--  les tâches de ce groupe reçoivent les ressources une par une
--  et attendent d'avoir toute leur requête avant de continuer
--  les autres tâches en attente, s'il y en a, sont servies après.
--  =============================================

package Allocation2 is
   Max : constant Integer := 100; --  nombre de ressources
   type Des_Ressources is new Integer range 0 .. Max;
   subtype Nb_Ressources is Des_Ressources range 1 .. Des_Ressources'Last;
   type Liste_Resource is new Integer; --  à modifier ultérieurement
  
Taille_Groupe :
constant Integer := 10
      --  nombre de tâches distinguées
   type Index_Groupe is mod Taille_Groupe;
   type Gestion_Groupe is array (Index_Groupe) of Des_Ressources;

  protected Controleuse is
      entry Demander (R : out Liste_Resource; Nombre : Nb_Ressources);
      procedure Rendre (R : in Liste_Resource; Nombre : Nb_Ressources);
   private
      entry Servir (Index_Groupe)
        (R : out Liste_Resource; Nombre : Nb_Ressources);
      Disponible : Des_Ressources := Des_Ressources'Last;
      Deficit : Gestion_Groupe; 
                --  tableau des ressources encore attendues
      J : Index_Groupe := Index_Groupe'Last; -- témoin de parcours
      function Recevable return Boolean;
  
end Controleuse;
end
Allocation2;

package body Allocation2 is
  
protected body Controleuse is
     
function Recevable return Boolean is
         --  il suffit d une place non utilisée, c'est à dire vide
         --  la sémantique de l'objet protégé garantit 
         --  qu'avant ce test
         --  toute entrée de Servir qui a sa garde à vrai, 
         --  parce que la place est vide, a été activée
      begin
         for K in Index_Groupe loop
            if Deficit (K) = 0 then
               return True;
            end if;
         end loop;
         return False;
      end Recevable;

      entry Demander 
            (R : out Liste_Resource; Nombre : Nb_Ressources)
      when Recevable is
         I : Index_Groupe;
        
function Index_Disponible return Index_Groupe is
         begin --  choix selon la politique d'allocation
            for K in Index_Groupe loop
               if Deficit (K) = 0 then
                  return K;
               end if;
            end loop; --  Recevable => on est sûr d'en trouver un
            raise Program_Error; --  ne doit pas servir
         end Index_Disponible;

      begin
         if Nombre >= Disponible then
            Disponible := Disponible - Nombre; -- effet de la demande
            --  Fournir_Les_Ressources_Dans(R);
         else         --  la demande ne peut être satisfaite
            I := Index_Disponible;
            Deficit (I) := Nombre - Disponible;
            requeue Servir (I);
         end if;
      end Demander;

      entry Servir (for I in Index_Groupe)
                (R : out Liste_Resource; Nombre : Nb_Ressources)
      when Deficit (I) = 0 is
      begin
         --  Fournir_Les_Ressources_Dans(R);
         null;
      end Servir;

      procedure Rendre 
            (R : in Liste_Resource; Nombre : Nb_Ressources) is
         Compte_Des_Nuls : Integer := 0;
         Nb : Nb_Ressources := Nombre;
      begin
         --  Recuperer_Les_Ressources_De(R) ;
         --  attribution de ressource, une par une, 
         --  à tour de rôle, à chaque requête J en attente, 
         --  connue parce que Deficit(J) > 0
         loop
            J := J + 1; --  Progression de l'indice de parcours
            if Deficit (J) > 0 then
               Compte_Des_Nuls := 0;
               Deficit (J) := Deficit (J) - 1;
            else
               Compte_Des_Nuls  := Compte_Des_Nuls  + 1;
            end if;
            Nb := Nb - 1;
            exit when (Nb = 0) or (Compte_Des_Nuls = Taille_Groupe);
         end loop;
         Disponible := Nb; -- reste = ressources non réparties
      end Rendre;
   end Controleuse;

begin
   null;
end Allocation2;

--   <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
--   voici  de quoi essayer les allocateurs 
--   chaque générateur de nombres aléatoires est partagé
--   et en accès concurrent; il doit être protégé

--   <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

--====================================

generic
   type Resultat is private;
   type Etat_Interne is limited private;
   with procedure Reset (V: in Etat_Interne);
   with function Prochaine_Valeur (V: Etat_Interne) return Resultat;

package
Machine_Protegee is
    function Prochaine_Valeur_Protegee return Resultat;
end
Machine_Protegee;

package body Machine_Protegee is
  protected Machine_Interne is
      procedure Reset_Interne;
      function Prochaine_Valeur_Interne return Resultat;
   private
      Etat : Etat_Interne;
  end Machine_Interne;

  protected body Machine_Interne is
      function Prochaine_Valeur_Interne return Resultat is
      begin
         return Prochaine_Valeur(Etat);
      end Prochaine_Valeur_Interne;
      procedure Reset_Interne is
      begin
         Reset (Etat);
      end Reset_Interne;
   end Machine_Interne;

   function Prochaine_Valeur_Protegee return Resultat is
   begin
      return Machine_Interne.Prochaine_Valeur_Interne;
   end Prochaine_Valeur_Protegee;

begin
   Machine_Interne.Reset_Interne; 
end Machine_Protegee;

--  =============================================
--  PROGRAMME PRINCIPAL
--  =============================================

with Ada.Text_IO; use Ada.Text_IO;
with
Ada.Numerics.Discrete_Random;
with
Ada.Numerics.Float_Random;
with
Allocation1; use Allocation1;
with
Allocation2; use Allocation2;
with
Machine_Protegee;

procedure Exemple_Ressource_Allocation is
  
package R_Number_Random is new
     Ada.Numerics.Discrete_Random (Allocation1.Nb_Ressources); 

   package Protected_R_Random is new Machine_Protegee
     ( Resultat         => Allocation1.Nb_Ressources,
       Etat_Interne     => R_Number_Random.Generator,
       Reset            => R_Number_Random.Reset,
       Prochaine_Valeur => R_Number_Random.Random);

   package Protected_Float_Random is new Machine_Protegee
     ( Resultat         => Float,
       Etat_Interne     => Ada.Numerics.Float_Random.Generator,
       Reset            => Ada.Numerics.Float_Random.Reset,
       Prochaine_Valeur => Ada.Numerics.Float_Random.Random);

   task type Pilote_Type (X : Allocation1.Nb_Ressources := 
                Protected_R_Random.Prochaine_Valeur_Protegee);

   task body Pilote_Type is
      R : Allocation1.Liste_Resource;
     
D1: Float := Protected_Float_Random.Prochaine_Valeur_Protegee;
      D2: Float := Protected_Float_Random.Prochaine_Valeur_Protegee;

      task Copilote;
      task body Copilote is
         Y : Allocation2.Nb_Ressources :=
Allocation2.Nb_Ressources (X);
         R : Allocation2.Liste_Resource;
      begin 
        
delay (Duration (D1)); --  attente aléatoire
         Put_Line (" cas 2 : demande de  " &
Allocation2.Nb_Ressources'Image (Y));
         Controleuse.Demander (R, Y);
         delay (Duration (D2)); --  attente aléatoire
         Put_Line (" cas 2 : retour de  " &
Allocation2.Nb_Ressources'Image (Y));
         Controleuse.Rendre (R, Y);
      end Copilote;

   begin
      delay (Duration (D1));  --  attente aléatoire
      Put_Line (" cas 1 : demande de  " &
Allocation1.Nb_Ressources'Image (X));
      Controleur.Demander (R, X);
      delay (Duration (D2)); --  attente aléatoire
      Put_Line (" cas 1 : retour de  " &
Allocation1.Nb_Ressources'Image (X));
      Controleur.Rendre (R, X);
   end Pilote_Type;

   Usagers : array (1..30) of Pilote_Type;

begin  -- maintenant on a soixante et une tâches actives
        -- leur exécution va donc imprimer 120 lignes de texte
   null;
end
Exemple_Ressource_Allocation;

retour à l'appel

--====================================

Un exemple de programmation distribuée

La programmation distribuée revient à découper un programme en plusieurs exécutables (appelés partitions en Ada) devant s'exécuter sur des machines (voir des OS) différentes. Une grande force de l'approche distribuée d'Ada et de permettre que le même programme puisse être compilé en mode distribué et non-distribué. Cette approche simple et pragmatique permet de rapidement construire une application distribuée, atout qui sera apprécié lors de l'enseignement (il n'est pas nécessaire de rentrer dans des détails de bas niveau). Pour illustrer ce point, prenons comme exemple une version distribuée du fameux Hello World !

Le serveur :

package Hello_Server is
    pragma Remote_Call_Interface;
    function Message return String;
end Hello_Server;

package body Hello_Server is 
    function Message return String is
    begin
        return "Hello World!";
    end Message;
end Hello_Server;


Le client :

with Ada.Text_Io;
with Hello_Server;

procedure Hello_Client is
use Ada;
begin
    Text_Io.Put_Line (Hello_Server.Message);
end Hello_Client;


La seule addition par rapport à la version non-distribuée est le pragma Remote_Call_Interface. On peut difficilement faire plus simple !

retour à l'appel

La solution
de la devinette (Ada, C, +, for, requeue, to, at)       c'est  :       

  Ada c’est plus fort que tout ! Ah !

Il s'agit évidemment d'une parodie de : Séga c'est plus fort que toi ! (bien connu des accros aux consoles !)

retour au plan

Retour page perso D. Feneuille

Retour site Ada France