Miguel Moquillon wrote:
Laurent Deniau wrote:
Attention, ce n'est pas function(arg1, arg2) mais function(obj1, obj2)!
La methode invoquee depende de obj1 *et* obj2. Une multi-methode donc.
...
Quelle extension de syntaxe utiliserais-tu pour un appel
de multi-methode en Objective-C ou en C++?
Je n'aime pas cette expression de multi-méthode parce qu'elle amène à penser
d'une certaine façon cette caractéristique. Je lui préfère le terme anglais multi-dispatching qui est plus ouvert.
C'est deux choses differentes a mon sens. Multi-methode implique que la methode est specialisee pour plusieurs classes a la fois. Le multi-dispatching est le mechanisme pour trouver de telles multi-methodes et il y a plusieurs techniques pour le faire. Apparament les papiers que tu me cites ci-dessous on le meme vocabulaire et utilise multi-methode dispatch (cf 2.1) qu'il abbrege par la suite en multi-dispatch.
Le langage Slate, qui est un langage objet à prototype basé sur la syntaxe
Smalltalk, et donc sur le modèle langage, implémente cette caractéristique.
Le site de Slate: http://slate.tunes.org/
Deux papiers sur le multi-dispatching écris par les concepteurs de Slate: - Prototype With Multiple Dispatch: http://tunes.org/~eihrul/pmd.pdf
- Prototypes With Multiple Dispatch: An Expressive and Dynamic Object Model:
http://tunes.org/~eihrul/ecoop.pdf
Je ne connais pas Slate, mais je vais lire ca. Ca a effectivement l'air interessant. Je vois neanmoins deja un probleme: la definition de la classe declare les methodes qu'elle implemente, d'ou la possibilite d'une syntaxe lie a l'instance (comme en C++ ou Java) mais aussi la difficulte d'ajouter des methodes a une classe incomplete. En COS (comme en CLOS ou Dylan), des methodes peuvent etre ajoute a volonte et ce n'importe ou. Si ces methodes accedent aux champs des instances, elles ont besoin de la definition de la classe, sinon ce n'est pas utile. C'est un des aspects fort de l'ADT des classes. En COS ca donne (en C99):
** generic.h // prototypes
[...]
defgeneric (object, gPrint);
defgeneric (object, gMoveToXY, int, int);
defgeneric2(int , gEqual); // multi-methode d'ordre 2
** generic.c // objets associes aux prototypes
[...]
makgeneric (object, gPrint);
makgeneric (object, gMoveToXY, int, int);
makgeneric2(int , gEqual);
** Point.h // definition de classe
#include <cos/object.h>
defclass(Point)
int x,y;
endclass
** Point.c // objets associes a la classe + qques methodes
#include <stdio.h>
#include "generic.h" // generic coupling (verbs)
#include "Point.h" // class coupling (nouns)
makclass(Point);
defmethod(object, gPrint, Point)
printf("(%d,%d)\n", Self->x, Self->y);
return self;
endmethod
defmethod(object, gMoveToXY, Point, int x, int y)
Self->x += x, Self->y += y;
return self;
endmethod
** Point_extend.c
#include "Point.h"
#include "generic.h"
defmethod2(int, gEqual, Point, Point)
return Self1->x == Self2->x && Self1->y == Self2->y
endmethod
** main.c
#include "generic.h"
useclass(Point); // weak class coupling
int main(void) {
object pt = gNew(Point);
object pt2;
gMoveToXY(pt, 10, 12);
gPrint(pt);
pt2 = gClone(pt);
gPrint(pt2);
printf("pt == pt2: %d\n", gEqual(pt, pt2));
gDelete(pt);
gDelete(pt2);
}
C'est très intéressant et ceci peut, peut-être, te donner quelques idées.
Peut-etre je vais regarder en details tout ca, mais les choses sont deja tres clair dans ma tete. Et cote syntaxe, les macros du C ne peuvent pas faire des miracles (quoique). Si
obj = gAdd(obj1,obj2);
ne convient pas, je dois passer par une macro pour en changer la syntaxe, parce que gAdd est en fait un prototype qui definit le generic (prototype + fonction inline + objet instance de Generic[Multi]Method) et en C il n'y a pas plusieurs facon de declarer un prototype. De plus en C89, cela veut dire que qqpart le nombre d'argument est specifie. Par exemple en OOC j'ai
call (obj, copy, obj2); // C99
call1(obj, copy, obj2); /* C89, le 1 precise la presence d'obj2 */
Avec l'experience, ce n'est pas du tout un probleme et devient rapidement naturel.
Qui plus est cette macro evalue deux fois obj sauf si on compile avec gcc.
call(obj, print); // equivalent a obj->_isa->print(obj);
Pour evite cet effet de bord invisible, call impose a obj d'etre une lvalue ce qui empeche a obj d'etre un appel de fonction. Le contre coup c'est qu'on ne peut pas chainer syntaxiquement les appels vituels.
call(call(obj, mth1), mth2); // ne compile qu'avec gcc
a+, ld.