Enseigner Ada, pourquoi ?, à qui ?, comment ? Choisir un langage : entre le tentant et le raisonnable !


précédentsommairesuivant

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

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

 
Sélectionnez
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).

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.

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

C. « 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

D. 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 œuvre 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.

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

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

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

H. Classes et objets

Une lecture superficielle du manuel de référence Ada (ah la norme !) pourrait laisser croire qu'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.

I. 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é. .

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


précédentsommairesuivant

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Copyright © 2003 Daniel Feneuille Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.