• Aucun résultat trouvé

pour chaque classe. On peut également dériver naturellement un langage de types L : chaque symbole de classe C joue le rôle d’un constructeur de type d’arité égale au nombre de variables de types qui paramètrent la classe. Par exemple Listest un constructeur d’arité 1 car cette classe accepte une variable de type α.

Il y a beaucoup plus de choix pour dériver l’algèbre de types utilisée A. Comme mentionné au chapitre 3, on peut choisir de travailler avec des termes finis ordonnés structurellement, avec des termes infinis, ou bien rationnels. On peut saturer l’ordre partiel obtenu pour en faire un treillis, ou un demi-treillis, ou bien garder l’ordre partiel arbitraire, etc.

Après avoir choisir l’algèbre de types à utiliser, il convient de vérifier qu’elle permet bien de construire un modèle de L et des représentations syntaxiques des éléments de base. En pratique ce n’est pas un problème car toutes ces algèbres sont des algèbres de termes.

Le choix de l’algèbre de types est donc l’élément crucial. Il est important de comprendre que chacune de ces algèbres aboutit à un système de types a priori différent, c’est-à-dire qu’il va rejeter plus ou moins de programmes. Par exemple, dans l’algèbre des termes finis structurels, la contrainte ∃α : α 6 α → α n’est pas satisfiable. En revanche, elle est satisfiable dans l’algèbre structurelle avec termes infinis ou récursifs. Elle est aussi satisfiable si l’algèbre est un treillis (prendre α = ⊥). Par ailleurs, les systèmes de type issus d’algèbres différentes auront également une complexité a priori différente. Par exemple, considérons simplement le problème de satisfiabilité d’une contrainte ∃α : κ. Dans une algèbre treillis, ce problème est typiquement traitable en temps polynomial O(n3)[Pal95].

En revanche, dans l’algèbre des termes finis ordonnés structurellement, le problème est PSPACE- complet [Tiu92, Fre97].

Au final, on se rend compte que l’un des avantages de notre approche algébrique est qu’elle permet de bien séparer trois aspects du systèmes de type : la correction, l’implémentation et la conception du langage. En particulier, il est possible de faire varier l’algèbre de types et de prouver très facilement la correction du système qui en résulte. Cela permet de se concentrer sur la conception du langage (quelles déclarations offrir ? quelles programmes rejeter ?) et sur l’implémentation du typage (quelles algorithmes pour résoudre les contraintes ?).

7.2

Monde ouvert

Jusqu’à présent, nous avons fait comme si le langage était un tout fermé : une fois fixé un ensemble de déclarations de classes, on peut écrire, typer et exécuter une expression. En réalité, un langage à objets réaliste est ouvert, c’est-à-dire qu’il permet d’écrire des modules réutilisables. En pratique, cela signifie qu’un module peut être typé et compilé dans une certaine hiérarchie de classes, mais qu’il est finalement exécuté dans une autre hiérarchie.

Prenons l’exemple d’un module M spécialisé dans le traitement des points. Il est typiquement compilé dans une hiérarchie H1 définissant les classes Point et Point3D. Cependant, au moment

où le module est exécuté, le programmeur a pu ajouter les classes ObjetColoré, PointColoré et

Point3DColorépour former la hiérarchie H2qui est de ce fait uneEXTENSIONde H1.

Notons que les expressions dans le module M, les définitions de méthodes par exemple, sont syntaxiquement bien formées dans la structure de classes dérivée de la hiérarchie H2 car celle-ci

se contente de rajouter des classes à H1 et ne modifie pas les champs des classes existantes. Si ces

formées quand on passe de H1à H2car on a simplement de nouveaux constructeurs de type et on ne

touche pas à l’arité des constructeurs existants.

Du point de vue de l’exécution, on remarque que la sémantique opérationnelle de ces expressions est plus générale dans H2que dans H1car elles peuvent traiter des objets construits avec des classes

inconnues de H1, ce qui est bien le but recherché du « polymorphisme à objets ».

Qu’en est-il du typage ? Si M est bien typé dans H1, il est en général faux qu’il soit également

bien typé dans H2. Par exemple, plaçons-nous dans l’algèbre des termes finis structurels et supposons

que le typage de M selon l’algorithme du chapitre 6 produise entre autres le problème d’implication suivant :

∀α . α6Point3D⊃Point3D6 α

Dans le modèle M1 dérivé de H1, cette implication de contrainte est vraie, parce quePoint3D n’a

pas de sous-type strict et donc la seule solution de la contrainte de gauche est α 7→ Point3D. En revanche, dans le modèle M2dérivé de H2, l’implication n’est plus vraie car α peut prendre la valeur

Point3DColoréqui est bien un sous-type dePoint3Dmais n’en est pas un super-type.

Il semble donc qu’il ne soit pas possible de typer le module M sans savoir dans quelle hiérarchie il va être exécuté. Cela va à l’encontre d’un principe de la programmation modulaire et de la compilation séparée qui voudrait qu’on puisse toujours typer un module indépendamment de son utilisation.

Pour traiter ce « typage ouvert » ou typage en « monde ouvert », remarquons d’abord que notre approche algébrique fournit un moyen très simple pour exprimer le résultat attendu. Pour typer un module M écrit dans une hiérarchie H1, on commence par extraire une liste de problèmes de typage

P1, . . . ,PNselon l’algorithme du chapitre 6. Il suffit alors de résoudre les problèmes Pi simultanément

dans toutes les extensions de H1.

Précisons maintenant ce qu’on entend exactement par extension. Pour que H2 étende H1, un

certain nombre de conditions sont nécessaires : H2peut ajouter des classes, mais ne doit pas modifier

le caractère concret ou abstrait d’une classe existant. Elle ne doit pas non plus modifier les relations de sous-classement existantes. Elle ne peut ajouter des champs à des classes existantes, ni modifier leur type.

En pratique, ces conditions sont nécessaires mais elles sont souvent trop générales pour modéliser les extensions qui sont effectivement exprimables dans un langage de programmation donné. Les extensions exprimables peuvent être limitées par la forme syntaxique des déclarations de classes. Par exemple, dans la syntaxe suggérée ci-dessus, on peut rajouter des classes uniquement par le bas. C’est-à-dire qu’une nouvelle classe ne peut être rajoutée comme super-classe d’une classe existante. Dans d’autres syntaxes et donc dans d’autres langages, l’extension par le haut peut être autorisée. Par exemple, si on introduit la classe abstraite Copiable des objets copiables, c’est-à-dire qui peuvent être passés à une méthode copy, alors on peut vouloir autoriser après coup la classePointà être une sous-classe deCopiable.1

De la même façon que le choix de l’algèbre de types conditionne le système de typage fermé obtenu, on peut remarquer que le choix de la notion d’extension de hiérarchie détermine également la puissance du système ouvert qu’on peut en dériver. Par exemple, considérons le problème d’implica-

1Un langage qui autoriserait cette possibilité devrait probablement prévoir de la restreindre aux classes commeCopiable