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).

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).

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.

La réutilisabilité : c'est l'aptitude d'un logiciel à être repris, en partie ou même en totalité, pour développer de nouvelles applications . On parle alors volontiers de composants logiciels à l'instar des composants que l'on réutilise en électronique.

L'extensibilité : c'est la facilité d'adaptation d'un logiciel aux changements de spécifications . évolution de la structure de données ou ajout de fonctionnalités sont souhaitables. Ceci impliquant des modifications rapides et .... fiables ! permettant une maintenance adaptative sûre.

La portabilité : c'est la possibilité pour un produit logiciel de ne pas dépendre d'un environnement matériel, ni d'un système, ni d'un compilateur particulier, c'est particulièrement important pour des applications numériques. La portabilité facilite le transfert d'une configuration matériel et / ou d'un système logiciel à un autre

La testabilité : c'est la mise en oeuvre de processus agressifs dont le but est de trouver des erreurs dans un logiciel. Cette phase du développement d'un logiciel est capital mais souvent négligée ou bâclée . Cette étape se prépare avant l'implémentation car on construit les plans de tests avant le codage (pendant les étapes de conception).

La maintenabilité : c'est l'aptitude d'un logiciel à être modifié élégamment, rapidement, sans remettre en cause fondamentalement la structure déjà spécifiée ni les applications existantes. Maintenance corrective cela s'entend mais aussi maintenance adaptative.

La lisibilité : c'est la propriété d'un code accessible et compréhensible rapidement par un plus grand nombre de développeurs. La verbosité d'un langage parfois décriée peut devenir une qualité. A titre d'anecdote on pourrait montrer le traditionnel « Bonjour le Monde » à des non spécialistes, dans différents langages, la version Ada est la plus lisible (même comparée à Pascal !). Deux autres exemples ?

La facilité de certification et de validation : c’est l’aptitude d’un logiciel à pouvoir être associé à des propriétés prouvant qu’il respecte ses spécifications, qu’il se termine correctement ou qu’il ne se bloque pas dans des situations de saturation de charge ou de manque de ressource. L’existence d’un langage normalisé et de possibilités de vérifications statiques contribuent à satisfaire cet objectif.

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).

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

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

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

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

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

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

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

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.

Leur « matériau de base » est formé par des étudiants possédant la maturité (« bac ») professionnelle technique obtenue après (ou pendant) un apprentissage fortement orienté vers la pratique professionnelle. Cette maturité est donc différente de la maturité académique (bac) obtenue dans les gymnases suisses (équivalents aux lycées français). A noter que les porteurs de maturité gymnasiale sont soumis à un stage préalable d’une année. Les porteurs de diplôme IUT sont admis en deuxième année d’études.

Les cours totalisent 34 heures de présence obligatoire par semaine sur 2 semestres de 17 semaines, plus 2 semaines spéciales (séminaires, etc.). Le style d'enseignement se caractérise par un fort encadrement (classes ne dépassant pas 30 étudiants, laboratoires en groupe de 10-15 étudiants et généralement bien équipés).

Le travail de diplôme de trois mois à plein temps est souvent proposé par l'industrie et sa soutenance a lieu en présence d'experts externes provenant des milieux professionnels et académiques. Les filières de formation sont évaluées périodiquement par des commissions d'experts internationaux (Peer Review), mandatées par l'OFFT (Office fédéral de la formation et de la technologie). Sont évaluées les prestations d'enseignement, de Ra&D, de mandats et de contacts avec les industries, la post-formation et les relations internationales.

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.

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.

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 ?

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.

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

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

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

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

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

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

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

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

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

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 !)