Surcharge d`opérateurs en Java

publicité
Surcharge d’opérateurs en Java
Philippe Baqué
Charles-Félix Chabert
Yannis Juan
Christian Delbé
Encadré par Thomas Graf
8 avril 2002
Résumé
Lancé en 1995 par Sun Microsystems, le langage Java ne cesse de
s’imposer au grand public, et séduit de plus en plus d’utilisateurs. Ce
succés est sans précédent, puisque jamais dans l’histoire de l’informatique, un langage de programmation n’a été aussi rapidement diffusé et
adopté.
Cette popularité ascendante est motivée par les nombreuses spécificités
intéressantes du langage (qui a aussi bénéficié d’une trés large médiatisation).
Parmis ces caractéristiques, les plus pertinentes nous semblent-être d’une
part la capacité de Java à être facilement diffusé sur le réseau grâce à
un interfacage trés simple avec celui-ci, d’autre part une interface de
programmation très compléte et efficace, et enfin la fameuse portabilité
de Java : “Write once, run everywhere”.
Malgré cela, Java posséde quelques défauts inhérents à sa conception,
à savoir une certaine lourdeur dans son interprétation. De même, il
n’existe pas d’intermédiaire entre les types primitifs et les objets référencés,
ce qui le condamne à être peu efficace en ce qui concerne le calcul
numérique.
Permettre aux utilisateurs de surcharger les opérateurs numériques nous
semble être une bonne approche pour définir les bases de ce qui pourraitêtre une implémentation plus efficace et plus commode pour le calcul
numérique en Java.
Nous allons à travers ce rapport introductif voir les différentes approches
que nous privilégions, celles que nous écartons, et enfin nos motivations.
1
1 Présentation du sujet
Le sujet de ce projet est de proposer la spécification d’un modèle de surcharge d’opérateurs en Java, ainsi qu’une implémentation de référence. Cette
implémentation sera intégrée au compilateur KJC [1]. Ce sujet, et la façon
dont il a été posé, nous laissent à priori une grande liberté dans les choix de
conception (approche par compilateur ou par préprocesseur, ...) et dans l’impact sur le langage Java (avec ou sans nouveau mot clé, modification de la
grammaire, ...).
Cette fonctionnalité est très peu présente sur le “marché” des compilateurs
(ou préprocesseurs) Java étendu, peut-être parce que c’est un sujet très controversé : l’utilité et les effets néfastes de la surcharge d’opérateurs (on traitera
de cette controverse dans la section 2). De plus, les quelques implémentations
existantes sont assez pauvrement documentées, et pas toujours clairement
spécifiées. Ce désert a rendu la tâche ardue mais attractive et concrète. On
va montrer dans la suite de ce document comment nous allons essayer de
construire un point d’eau dans ce désert.
2 Motivations
2.1 Les détracteurs
De nombreux langages objets, comme C++, Eiffel ou C#, proposent la surcharge d’opérateurs. Mais Java n’implémente pas cette fonctionnalité. Nous
nous sommes demandé pourquoi, et la raison qui semble ressortir est le souci
de simplicité [2] :
Java omits many rarely used, poorly understood, confusing
features of C++ that in our experience bring more grief than benefit. These omitted features primarily consist of operator overloading (also the Java language does have method overloading),
multiple inheritance, and extensive automatic coercions.
Mais à quel prix ? C’est un vieux débat de l’informatique : simplicité contre
expressivité. Guy Steele [3] apporte sa solution : l’évolutivité d’un langage, et
qualifie Java de langage évolutif.
2
Alors, si cette évolutivité permettrait d’apporter à Java la surcharge d’opérateurs,
pourquoi ne pas le faire? Certains répondrait :
– “Si Sun ne l’a pas fait, c’est que ce n’est pas une bonne chose ou que
c’est impossible !”. Nos lectures pendant la préparation de ce rapport
nous ont appris à démythifier Sun, et à voir les programmeurs humains
derrière ce sigle (on fera référence surtout à [4], qui présente les principaux défauts, selon l’auteur, de Java). De plus, si Java se dit évolutif,
c’est bien pour le faire évoluer !
– “La surcharge d’opérateurs est un luxe dont on peut se passer.”. Alors,
à l’extrême, pourquoi ne pas programmer en assembleur?
– En ce qui concerne l’éternelle “illisibilité” que provoquerait la surcharge d’opérateurs, nous pensons que cet argument n’est pas recevable : même James Gosling [5], pourtant au début opposé à la surcharge d’opérateurs, avoue :
And if you look at people who are doing complex arthmetic
in Java right now, it’s really ugly. I mean, it’s unbelievably
ugly.
– “Un programmeur peut définir des opérateurs avec une sémantique bizarre, non-intuitive.”. Nous nous joignons à Conrad Weisert [6] pour
répondre :
Any programmer so undisciplined as to define + to do substraction is likely also to define add in the same misleading
way or to commit all sorts of other programming sins. Competent professionals are unlikely to do either.
2.2 L’intérêt
Le succés de Java est certes important, mais il y a une catégorie de programmeurs qu’il n’a pas conquis : les mathématiciens et tous ceux qui utilisent l’informatique à des fins majoritairement numérique. Ces personnes
reprochent à Java sa lourdeur d’écriture et son manque d’efficacité à ce niveau. Un exemple souvent cité est l’utilisation des nombres complexes : on
aimerait, pour ce type d’objet numérique, jouir des mêmes avantages que les
types primitifs, c’est à dire efficacité, utilisation des opérateurs arithmétiques
et sémantique par copie. Ainsi, nos recherches nous ont pratiquement toujours
ramené à ce même thème : l’extension de Java au niveau numérique. On citera
par exemple le projet JavaGrande [7], qui propose une approche intéressante
que nous développerons dans la section 4.
Le numérique semble donc être le talon d’achille de Java, et la surcharge
des opérateurs serait un pas en avant vers un Java plus universel.
3
3 Les implémentations existantes
Durant nos travaux de recherche préliminaires, nous avons rencontré deux
approches bien distinctes. Tout d’abord, celle qui consiste à faire passer un
pré-processeur sur le code et faire un remplacement textuel des opérateurs
par les méthodes correspondantes, et une autre, plus subtile, qui consiste à
introduire un nouveau type, pseudo-primitif, qui conserverait une sémantique
de passage par valeur et certaines propriétés des “classes lourdes”.
3.1 Les préprocesseurs
C’est le moyen le plus simple et le plus intuitif d’implémenter la surcharge
d’opérateurs. Dans les définitions des classes, on implémente les méthodes
surchargeant les opérateurs en leur donnant une syntaxe bien particulière. Ensuite, une fois notre programme principal écrit, on fait passer un préprocesseur
qui se charge de remplacer textuellement les opérateurs par les appels de
méthodes correspondants. C’est une approche purement syntaxique pour laquelle nous n’avons trouvé que peu d’exemples. L’un d’entre eux, JFRONT
):
définit ses classes comme ceci (par exemple la classe
!
"#$%#$'&#(%#)*
!
+%,-).
/
3
4
021 0
&5,-).
6
3
4
021780
95,-).
3
9%,:<;=&>3
4
Aprés passage du préprocesseur, on obtient le source suivant :
"#$%#$'&#(%#)*
!
+%,-).
/
3
4
021 0
&5,-).
6
3
4
021780
95,-).
3
9%,+? 8@?&443
Nous avons également pu observer une autre approche, qui consiste à introduire un nouveau type, pseudo-primitif, pour lequel on pourrait surcharger
les opérateurs.
3.2 Un type pseudo-primitif
Il existe deux sortes de types en Java, les classes qui ont une sémantique
par référence, et les types primitifs qui ont une sémantique par copie. L’idée
est d’offrir à l’utilisateur un nouveau type, orienté numérique qui conserverait
un peu des propriétés des deux précédents. Cette idée est lancée par Bill Joy
)
, qui est une extension du langage Java écrite par
[8]et est reprise par A
Joseph D. Darcy [9].
Si l’utilisateur définit un nouveau type arithmétique, alors il est désirable
que celui-ci ait une sémantique par copie, c’est à dire analogue à celle des
types primitifs. De même, on aimerait conserver la notation infixe propre aux
mathématiciens, d’ou la necessité de pouvoir surcharger les opérateurs.
&
Borneo introduit un nouveau mot-clé,
qui agit comme un modifica&
teur de classe. Seules les classes déclarées comme
peuvent définir des
méthodes permettant la surcharge d’opérateurs. De plus, pour pouvoir per)
inimettre à ces classes de se comporter comme des types primitifs, A
tialise par défaut tous les champs de ces classes.
4 Notre approche
L’approche que nous allons présenter ici est celle qui nous semble aujourd’hui la plus intéressante : c’est celle qui consiste à introduire un type
pseudo-primitif. Elle est axée principalement sur l’extention de Java au niveau numérique, et s’appuie sur les propositions de JavaGrande [7], ainsi que
sur l’implémentation existante Borneo [9].
5
4.1 Critique des approches précédentes
La section précédente nous a présenté les différentes approches que nous
avons pu rencontrer. L’idée la plus intuitive est celle d’un préprocesseur, mais
un tel système de réecriture ne tiendrait compte d’aucune sémantique, et laisserait trop de responsabilités au programmeur quant à la définition de cette
sémantique. De plus, ce système n’apporterait rien d’autre qu’une facilité
d’écriture et n’enrichirait pas la sémantique de Java. On aurait alors un outil pour Java et non plus une extension de Java.
Une seconde approche, que nous n’avons pas rencontrée mais qui est celle
de C++, serait d’intégrer la surcharge d’opérateurs dans le compilateur de
façon “totale”, c’est à dire permettre de définir et de surcharger tous les opérateurs
pour toutes les classes. Bien que sémantiquement plus riche et plus robuste
que l’approche par préprocesseur, cette méthode ne nous a pas séduite parceque la sémantique par référence de Java n’est pas adaptée à la surcharge
d’opérateurs et au calcul numérique en général.
4.2 Notre choix
L’approche que nous avons choisie s’inscrit dans un projet de plus large
envergure, l’extension de Java au niveau numérique. Ce projet est principalement représenté par JavaGrande [7], qui comporte d’autres points que la
surcharge d’opérateurs que nous n’aborderons pas ici. En effet, de part son
état de langage objet qui rend toutes données, ainsi que leur manipulation,
“lourdes”, et de part sa sémantique par référence (hors types primitifs), Java
n’est pas un langage numérique.
Les opérateurs arithmétiques ne sont utilisables qu’avec les types primitifs,
#)C
. Ils utilisent un passage de paramètres par
exception faite de la classe B
valeur. La surcharge d’opérateurs demande donc de garder cette sémantique
pour le calcul numérique si l’on veut lever le maximum d’ambiguités dans
son utilisation, or les objets en Java ne sont manipulés que par référence.
C’est pour cette raison que la surcharge d’opérateurs nécessite un type particulier permettant de simuler un passage par valeur. Il est important de noter
que ce type simule le passage par valeur, et sera finalement considéré par le
compilateur comme une référence, puisque la JVM n’accepte d’empiler que
des références, ormis les types primitifs.
C’est donc pour ce nouveau type, et seulement pour lui, que l’on permettra la surcharge des opérateurs arithmétiques, incluant l’affectation et la
comparaison.
6
4.3 Nos objectifs
Le planning de réalisation ne peut être établi de manière précise pour
l’instant mais sera bientôt disponible sur le site du projet. Il nécessiterait une
formalisation plus précise de l’approche et de ses implications, qui n’a pas pu
être faı̂te pendant nos premières recherches, principalement bibliographiques.
Nous définirons ensuite une spécification qui devra :
– minimiser l’impact sur Java, c’est à dire être une extension, pas une
modification de la JLS,
– ne nécessiter aucune modification de la JVM,
– définir un type hybride, avec une sémantique par copie,
– permettre la surcharge d’opérateurs pour ce type.
Une implémentation de référence sera réalisée et intégrée au compilateur
Java KJC [1].
7
5 Bibliographie
1.
2.
3.
4.
5.
6.
7.
8.
9.
@EFF ... ( FG#F($FG#
D
KJC Reference Manual. D
.
Sun Microsystems. The Java Language : An Overview.
G. L. Steele Jr. Growing a Language. 1998.
C. Weisert. The Dark Side of Java. 1997.
D. Boloker, C. Rumble, D. Tidwell. James Gosling : An interview with
the Java Guru. 1999.
C. Weisert. Conventions for Arithmetic Operations in Java. 1997.
Java Grande Forum Report. 1998.
B. Joy Proposal for Enhanced Numeric Programming facilities in Java,
Draft 3. 1997.
J. D. Darcy. Borneo 1.0.2. 1998.
Ces documents, ainsi qu’une mise à jour de l’état d’avancement du projet,
EFF$# )#$
:
F ("$F
H
sont disponibles sur D
.
8
Téléchargement