En rangeant des papiers pendant cette période lugubre dite « des fêtes » je suis tombé sur un texte que j'avais imprimé naguère, présenté comme le chapitre d'un livre (mais lequel ?), sans mention de nom d'auteur : Objets, classes, héritages : définitions. Je l'ai lu (relu ?) : il est fort bien écrit (ce qui est suffisamment rare dans ce genre littéraire pour être noté), témoigne d'une vaste culture tant informatique que logique et philosophique, et explique au bon niveau d'abstraction quantité de choses qui font trop souvent l'objet soit de survols inconsistants, soit de galimatias techniques privés de recul. En outre, le texte est suffisamment concis pour être saisi dans son entièreté sans trop de difficulté. Pour quelqu'un comme moi, qui suis loin d'être un expert des langages à objets, une lecture aussi instructive qu'agréable. Préciser le vocabulaire et les concepts n'est pas un luxe dans ce domaine où chaque langage de programmation a les siens.
Quelques indices repérés dans le texte et placés dans Google m'ont finalement révélé que ce texte de Jean-François Perrot était disponible sur le site d'un Colloque scientifique en l'honneur de ce professeur émérite du LIP6, qui soit dit en passant enseigne les langages réguliers à l'INALCO ! Voici quelques notions résumées que j'ai cru pouvoir en inférer.
J.-F. Perrot aborde le sujet à partir des techniques d'implémentation [1], ce qui est provocateur mais judicieux. Pour une démarche qui va sans arrêt se poser la question de la limite entre ce qui est abstrait et ce qui est concret, autant mettre tout de suite les pieds dans le plat, si j'ose dire.
Sous-classes et sous-types
Un sous-type, en général, est la restriction, par une définition plus précise, du type dont il est issu. Les opérations valides pour le type le sont pour le sous-type, qui est éligible pour des opérations supplémentaires. Pensons au type nombre, au sous-type nombre entier.
Une sous-classe est souvent une extension de la super-classe, par ajout d'attributs et de méthodes, mais aussi par remplacement de méthodes de la super-classe par des méthodes différentes, ce qui ne va pas sans créer des difficultés lorsque l'on tente de faire coïncider les notions d'héritage et de sous-typage : « le comportement significatif des instances de la sous-classe va être différent de celui des instances de la super-classe, et, en bonne logique, l'on ne pourra donc plus conclure comme précédemment que l'extension de la sous-classe est incluse dans celle de la super-classe ». (p. 20)
Un type est, en définitive, une collection de valeurs. Certains systèmes d'objets (Java notamment) utilisent une forme particulière nommée interface pour décrire les signatures de méthodes, c'est-à-dire en fait leur type. Une classe implémente (réalise) une interface lorsqu'elle en implémente toutes les méthodes.
Une classe est une collection d'objets mutables.
Il y a de bonnes raisons pour que les valeurs ne soient pas des entités mutables.
Classes, genres, espèces
Une classe abstraite est comme un genre : le genre félin spécifie un certain nombre de caractères que doit posséder un animal pour que l'assertion selon laquelle il est un félin soit vraie, mais ces spécifications ne suffisent pas à décrire un animal réel.
Une classe concrète est comme une espèce : les spécifications de la classe abstraite dont elle dérive sont complétées afin que les instances de cette classe soient des objets fonctionnels.
Une instance d'une classe est comme un individu d'une espèce.
Mais qu'est-ce qui est concret ou abstrait ici ?
« À l'intérieur de la machine, classes et instances ont la même consistance matérielle, à savoir des octets en mémoire. Les unes ne sont pas plus abstraites ou concrètes que les autres. C'est l'interprétation que nous faisons de l'implémentation esquissée ci-dessus qui assigne aux classes un statut d'abstractions (concepts) et aux autres un statut d'objets concrets (instances). Cette interprétation s'appuie sur une analogie : de même que le concept abstrait est unique vis-à-vis de ses réalisations concrètes, qui sont multiples, de même la classe est une, et ses instances sont (potentiellement) multiples. » (p. 16)
Querelles des universaux
« L'attention portée à l'objet individuel “concret” donne une nouvelle coloration à la distinction fondamentale entre concept (abstrait) et instance (concrète) du concept — alias définition/exemple, espèce/individu, etc. Il s'agit d'un très ancien problème, celui du statut des concepts abstraits. Platon les appelait les idées, et il pensait qu'ils existaient réellement dans le monde comme entités séparées. Aristote, critiquant son maître, estime au contraire que les concepts généraux ne sont que des attributs, inséparables des individus auxquels ils s'appliquent. Ce conflit se poursuit jusqu'à nos jours dans le débat entre nominalistes (qui suivent grosso modo Aristote) et réalistes (qui seraient du côté de Platon) avec, au Moyen-Âge, la fameuse “Querelle des Universaux”...
L'informatique suit une pente plutôt nominaliste. C'est la notion de type qui a occupé ce terrain, d'abord comme indications au compilateur sur l'organisation de la mémoire, ensuite comme annotations systématiques au texte du programme, donnant lieu au contrôle de types, enfin comme spécifications ou interfaces (types abstraits). » (pp. 7-8)
En informatique de manière générale, et dans le monde de la programmation avec des objets en particulier, cette controverse se concentre autour des notions de réification, d'introspection et de réflexivité (pp. 29-30). En programmation, l'opération de réification d'une entité consiste à en faire un objet du langage sur lequel le programme peut avoir une action ; si cette action consiste à modifier la valeur d'un attribut de l'objet en question, on dit que l'objet est devenu mutable. Si un message envoyé à cet objet permet d'obtenir en réponse des informations non seulement sur son état (la valeur d'un de ses attributs par exemple) mais aussi sur sa nature (de quels attributs est-il doté, et quel est leur nom ?), cet objet est dit doté d'une capacité d'introspection.
Les classes doivent-elles être réifiées, selon Platon, ou faut-il se rallier à Aristote pour dire qu'elles n'existent qu'en tant que modèles de création d'objets pendant l'élaboration du programme, et qu'au temps de son exécution elles ont disparu en tant que telles, pour ne plus subsister qu'à l'état de souvenir dans les instances qu'elles ont servi à réaliser ?
Ainsi, la réflexion sur la définition du langage Scheme (de la famille Lisp, que J.-F. Perrot range dans le camp « éminemment réaliste », p. 28) a soulevé une question de ce genre : faut-il réifier les environnements, qui sont au cœur du modèle d'évaluation de ce langage ? Un environnement est une liste de couples nom—valeur, où le programme trouve donc les valeurs des variables qu'il manipule. Puisque les Lispiens sont des réalistes, pourquoi ne pas tout réifier, y compris les environnements ? La voix de la sagesse s'est alors élevée pour dire qu'il y avait des limites aux réalisme : si un programme peut manipuler l'environnement dans lequel il s'exécute, il devient particulièrement difficile de prédire son comportement, pour ne rien dire de la possibilité de tenir un raisonnement à son sujet.
Pour paraphraser Chesterton, la conception d'un langage de programmation, de même que l'art et la morale, “consists in drawing the line somewhere”.
[1] Désolé si ce terme ne figure ni dans le Littré ni dans le TLF, mais il y manque ; ni implantation ni réalisation ne font l'affaire.