• Aucun résultat trouvé

2.2 La réflexivité en informatique

2.2.1 La réflexivité des langages interprétés

Un langage interprété L est réflexif s’il permet d’inclure dans un programme P écrit dans ce langage du code modifiant la manière dont L est interprété. Cette approche apparaît relativement naturelle, si l’on remarque qu’un langage de programmation (en dehors du langage machine) n’a, tel–quel, aucune signification « calculatoire » pour un ordinateur. Le mini–programme LISP’(+ 2 5)’ n’est pour un processeur que la concaténation des carac- tères ’(’, ’+, ’ ’ etc., et de même qu’un étudiant qui ne connaît pas le LISPne peut comprendre sa signification, un ordinateur ne peut l’exécuter sans posséder un interpréteur adapté. Pour reprendre nos termes de linguistique, ’(+ 2 5)’ n’est qu’un signifiant et c’est la sémantique du langage LISP définie par John McCarthy en 1958 qui permet de lui faire correspondre

une exécution (le signifié). Si John McCarthy n’avait pas inventé le LISP, nous pourrions toujours écrire la chaîne de symbole ’(+ 2 5)’, mais elle n’aurait pas de signification. En changeant d’interpréteur, on change la sémantique du langage, et donc la signification du programme. Un programme qui modifie son interpréteur modifie sa propre signification, et se modifie donc lui-même.

Deux problèmes se posent dans cette approche :

1. Comment éviter une récursion infinie dans l’interprétation d’un programme P , si P contient son propre interpréteur ?

2. Quels éléments de l’interpréteur rendre manipulables par P ? Pour reprendre la ter- minologie employée précédemment : quel méta-modèle du langage L proposer aux

programmes écrits avec L ? par l’intermédiaire de quelle méta-interface, par quels éléments du langage L, donner accès à ce méta-modèle ?

Interpréteurs réflexifs et méta-circularité

Le premier problème se résout en utilisant ce qui a été appelé un interpréteur méta- circulaire [Maes 1987]. Un interpréteur méta-circulaire donne accès à une représentation (méta-modèle) de son propre processus d’interprétation, et permet, en modifiant cette représentation, de modifier son propre fonctionnement. Le fait de rendre visible le processus d’interprétation est appelé réification, par emprunt au vocabulaire philosophique, ce qui signifie rendre concret une entité abstraite. Cette « réification » du travail de l’interpréteur permet de distinguer dans un programme Q qui en fait usage des zones qui modifient l’interprétation par défaut (Qr´ef lexif), et des zones qui produisent des résultats pour l’environnement extérieur au programme (Qbase) : Q= Qr´ef lexif ∪ Qbase. Si nous notons Id´ef aut l’interpréteur par défaut du langage L, l’interprétation du programme réflexif Q s’opère « conceptuellement » en deux temps : Id´ef aut interprète Qr´ef lexif, ce qui définit un nouvel interpréteur I1 = Id´ef aut ∪ Qr´ef lexif. C’est ce nouvel interpréteur I1 qui est finalement utilisé pour interpréter3la partie non–réflexive du programme, Q

base.

En incluant dans L des mécanismes pour décider qui interprète qui, il est alors possible d’inclure récursivement plusieurs niveaux d’interprétation Q1

r´ef lexif, Q 2

r´ef lexif, ... Qnr´ef lexif dans un programme. On obtient alors une « tour » d’interpréteurs. Cette tour se termine lorsque le programme à interpréter ne contient plus que des éléments non–réflexifs.

Choix du méta-modèle

Très souvent la partie réflexive d’un programme (Qr´ef lexif) ne redéfinit qu’une partie du processus d’interprétation défini par l’interpréteur par défaut (par exemple en rajoutant une fonctionnalité de traçage d’appels, ou en introduisant de nouveaux mots-clefs), et réutilise largement les fonctionnalités proposées par l’interpréteur original Id´ef aut. Dans une architecture réflexive, la structuration du méta-modèle exporté par l’interpréteur par défaut Id´ef autconstitue donc un choix essentiel parce qu’elle détermine dans quelle mesure et de quelle manière la sémantique du langage pourra être modifiée et étendue par un programme.

Par exemple le langage JAVA [Joy et al. 2000] possède certaines capacités réflexives, mais ces capacités ne fournissent que des moyens d’observation de relativement haut niveau du processus d’interprétation du byte–code JAVA. La partie réflexive de JAVA

met par exemple à disposition du programmeur des classes spécialisées telles que Class (les instances de Class, des objets donc, représentant les classes connues par la machine virtuelle JAVA), Method, ou Constru tor, et des méthodes telles que

3En pratique, ces deux temps de l’interprétation s’entrelacent, l’interprétation de chacune des lignes de Q

basefaisant

Class.getConstru tors() Class.getMethods() Method.invoke(..)

Constru tor.newInstan e(..).

Cependant il n’est pas possible dans JAVAde modifier l’interpréteur, en redéfinissant par

exemple le mécanisme d’invocation.

Terminologie niveau de base méta-niveau interfaces fonctionnelles méta- interfaces méta-modèle

FIG. 2.2 :Architecture d’un système réflexif

Les parties réflexives et applicatives d’un programme réflexif permettent de distinguer deux niveaux de fonctionnement dans ce programme. On parle de méta-calcul pour dési- gner l’activité du système lorsque celui-ci interprète les parties réflexives du programme (ces parties manipulent en effet des éléments qui représentent eux-mêmes un mode d’interprétation). Les zones du programme qui définissent ce méta-calcul constituent ce que l’on nomme le méta-niveau d’un programme réflexif. Par symétrie, on désigne la partie applicative (Qbase) comme étant le niveau de base de Q. Cette structuration est illustrée sur la figure 2.2. Le méta-modèle, qui rend accessible le processus d’interprétation du niveau de base, est le « connecteur conceptuel » qui permet au méta-niveau de modifier ce processus. Ce connecteur se concrétise pour le méta-niveau par une série de méta-interfaces qui lui fournissent des capacités d’observation et d’action sur les activités du niveau de base.

Les capacités d’observation utilisées par le méta-niveau sont classifiées en deux caté- gories. Lorsque le niveau de base notifie spontanément le méta-niveau d’une évolution sous la forme d’un évènement (l’invocation d’une méthode, la déclaration d’une nouvelle variable, l’instanciation d’un objet), l’on parle de réification. Ces notifications matérialisent pour le méta-niveau le processus d’interprétation qui a lieu au niveau de base. Lorsque le méta-niveau requiert explicitement une information (quelles variables sont connues, quels objets ont été instanciés, quelle ligne de programme est en train d’être interprétée...), l’on parle d’introspection. Enfin, on parle d’intercession pour les capacités d’action qui per- mettent au méta-niveau de modifier le processus d’interprétation du niveau de base. Sur la

figure 2.2 page précédente, ces différents modes d’interaction entre niveau de base et méta- niveau sont représentés par des flèches montantes et descendantes. La granularité de ces différentes capacités réflexives (réification, introspection, intercession) dépend du choix du méta-modèle, et détermine, comme nous l’avons illustré sur l’exemple JAVA, la nature plus

ou moins réflexive du langage considéré.

Cas particulier de l’orienté objet : les MOP

L’orienté objet permettant de structurer les logiciels de manière particulièrement flexible et modulaire, l’utilisation conjointe des paradigmes orienté objet et réflexif a très tôt reçue un intérêt marqué [Maes 1987, Kiczales et al. 1991]. L’ensemble du système étant orienté objet, le méta-niveau d’un système à la fois orienté objet et réflexif est lui aussi structuré sous forme d’objets particuliers, appelés méta-objets, qui encapsulent les aspects réflexifs du système. Ces méta-objets interagissent avec le niveau de base, organisé en objets de base, en utilisant les mécanismes de réification, introspection, et d’intercession que nous avons mentionnés. Du fait de la structuration en termes d’objets, on parle alors de protocole à méta-objets (MOP en anglais) pour désigner l’ensemble de conventions qui régissent les interactions entre méta-objets et objets de base, notamment en terme d’association (comment les méta-objets sont-ils associés aux objets de base ?), et de cycles de vie (comment les méta- objets sont ils créés ? détruits ? comment leur cycle de vie interagit-il avec celui des objets de base ?). Cette notion de MOP est à la base de la plupart des plates-formes réflexives que nous présentons dans la section 2.2.3.