120

Je ne voulais pas ouvrir un autre topic pour ça, alors je vais le poster ici :

Le prochain release de Moka sera multi plates-formes, je n'ai pas encore fait beaucoup de tests, mais voici la compilation d'un hello world :

http://quesoft.dyndns.org:8080/dev/moka/Screenshot.png

121

Je me suis un peu plus penché sur ton projet. J'ai regarder les sources, je suis même aller jusqu'à chercher d'autre "java2c" sur le net (Y'avais pas grand chose d'interessant à part p-e gcc-java (encore un gcc !) et un "jcc" dont je n'est pas reussi à avoir les sources). Et en fait j'ai été étonné qu'il n'y ait pas la fonctionnalité principale d'un langage OO qui est le polymorphisme : dommage.

Puis j'ai essayer d'imaginer comment j'aurais fait en java-moka un de mes programme que j'ai actuellement codé en C.
Et en fait je me suis rendu compte que pour la Ti, il faut en général à un moment où à un autre un accès direct à la mémoire, soit pour dessiner rapidement, soit pour écrire dans un fichier. Je me vois pas utiliser des outputstream sur une Ti...
Donc le java me parait finalement assez inapproprié. Je pense que de l'objet pour la Ti devrai plus ressembler à du C++.
Mais j'ai vu qu'il y avait la possibilité de faire des native{....} : est-ce la solution ? D'ailleurs je n'ai pas reussi à savoir comment sont reliées les variables internes au native et les variables du programme écrit en java-moka : par exemple, pour les paramètres d'une fonction native.

122

hibOu :
Je me suis un peu plus penché sur ton projet. J'ai regarder les sources, je suis même aller jusqu'à chercher d'autre "java2c" sur le net (Y'avais pas grand chose d'interessant à part p-e gcc-java (encore un gcc !) et un "jcc" dont je n'est pas reussi à avoir les sources). Et en fait j'ai été étonné qu'il n'y ait pas la fonctionnalité principale d'un langage OO qui est le polymorphisme : dommage.

En fait, Moka supporte le polymorphisme des méthodes et des objets. La seule limitation est que la signature d'un message est générée à la compilation et non à l'exécution (beaucoup plus rapide, mais beaucoup moins cool). Je vois mal comment on peut affirmer que Moka ne supporte pas le polymorphisme. Sans polymorphisme, explique ça :

//Une String est un Object
Object o = new String("Hello");

//Méthode surchargée
System.print("hello"); 
System.print(2345);
System.print(o);

String s = "toto";
if (o.equals(s)) { //O est un Object pour le compilateur, pourtant en runtime, la méthode de la classe String est invoquée ...

}

Captioned a = new Button(); // Captionned est une Interface
Captioned b = new Frame();

b.setCaption(s.toString()); // La méthode de la bonne classe est invoquée ... Button et Frame sont dans 2 branches différentes de la hiérarchie - Si ce n'est pas du polymorphisme ...

etc .


hibOu :
Puis j'ai essayer d'imaginer comment j'aurais fait en java-moka un de mes programme que j'ai actuellement codé en C.
Et en fait je me suis rendu compte que pour la Ti, il faut en général à un moment où à un autre un accès direct à la mémoire, soit pour dessiner rapidement, soit pour écrire dans un fichier. Je me vois pas utiliser des outputstream sur une Ti...


Utilise la classe moka.io.Graph qui est essentiellement un mapping des fonctions de Graph.h ou l'interopérabilité (permet de faire presque tout ce que l'on fait en C en Moka et essentiel à l'heure actuelle pour utiliser les fonction de vat.h - si qqn est intéressé à réimplémenter moka.io.File avec les fonctions de vat.h à la place de stdio.h, qu'il ne se gêne pas ... je devrai le faire un jour - parce qu'à d'autres endroits de l'API je l'utilise anyway) :

native.DrawLine ( 0, 0, 15, 15 , A_NORMAL );

hibOu :
Donc le java me parait finalement assez inapproprié. Je pense que de l'objet pour la Ti devrai plus ressembler à du C++.

Moka est assez proche de ce que serait une implémentation minimale du C++, sans la surcharge des opérateurs et avec un look-and-feel Java. Il est beaucoup plus léger que ces deux langages (mais moins puissant cependant). Je ne vois pas pourquoi un C++ 'light' serait nécessairement plus adapté aux TI68K que le Moka.

Évidemment, tout le monde a des goûts différents et le C++ est un langage très répendu. Je serais le premier à être content de voir un compilateur C++ viable apparaître pour les TI, mais je serais surpris qu'il soit moins lourd que Moka (là je ne parle pas de l'API, juste du langage - les programmes en C++ utilisent beaucoup de fonctions des libs standards du C, ce qui plus performant que de programmer en objet).

S'il implémente des features comme du polymorphisme pur à 100 % (i.e. que la signature du message est déterminé en runtime), alors il génèrera nécessairement des progs plus gros et moins rapides.
hibOu :
Mais j'ai vu qu'il y avait la possibilité de faire des native{....} : est-ce la solution ?

Oui, selon moi. Ça permet de proposer des classes avec une interface publique clean et implémentées de façon efficientes avec des hacks dirty en dessous (qui peuvent être remplacés au besoin sans rien affecter, merci encapsulation).
hibOu :
D'ailleurs je n'ai pas reussi à savoir comment sont reliées les variables internes au native et les variables du programme écrit en java-moka : par exemple, pour les paramètres d'une fonction native.


Moka est juste un gros préprocesseur,
native.DrawLine ( 0, 0, 15, 15 , A_NORMAL );


Est simplement traduit :
DrawLine ( 0, 0, 15, 15 , A_NORMAL );


Si je déclare :

int toto;


Dans le code C, on pourra voir :
long int toto;


Moka a beaucoup de limitations p/r au Java, mais il supporte correctement le paradigme OO (héritage, polymorphisme, encapsulation, résolution dynamique des méthodes).

En fait, ce que Moka fait le plus mal est l'encapsulation : oui, on peut encapsuler et ça marche très bien, mais Moka va laisser les programmeurs accéder intempestivement aux donnés default, private et protected s'ils le désirent.

123

Quesoft :
En fait, Moka supporte le polymorphisme des méthodes et des objets. La seule limitation est que la signature d'un message est générée à la compilation et non à l'exécution (beaucoup plus rapide, mais beaucoup moins cool). Je vois mal comment on peut affirmer que Moka ne supporte pas le polymorphisme. Sans polymorphisme, explique ça :

//Une String est un Object
Object o = new String("Hello");

//Méthode surchargée
System.print("hello"); 
System.print(2345);
System.print(o);

String s = "toto";
if (o.equals(s)) { //O est un Object pour le compilateur, pourtant en runtime, la méthode de la classe String est invoquée ...

}

Captioned a = new Button(); // Captionned est une Interface
Captioned b = new Frame();

b.setCaption(s.toString()); // La méthode de la bonne classe est invoquée ...
// Button et Frame sont dans 2 branches différentes de la hiérarchie - Si ce n'est pas du polymorphisme ...

etc .


en fait, j'appelle plutot cela de la surcharge. Mais on peut aussi appeler ca du polymorphisme (ad-hoc).
En fait, je sais plus trop comment s'appelle la fonctionnalité suivante :
Object s = new String("blabla");
System.out.println(s); //appelera println(String) et non println(Object)

Et ça je trouve que c'est l'essentiel d'un langage Objet.
Sans ça, je ne trouve que le langage ne devient qu'il simple surcouche syntaxique au C.
hibOu :
Puis j'ai essayer d'imaginer comment j'aurais fait en java-moka un de mes programme que j'ai actuellement codé en C.
Et en fait je me suis rendu compte que pour la Ti, il faut en général à un moment où à un autre un accès direct à la mémoire, soit pour dessiner rapidement, soit pour écrire dans un fichier. Je me vois pas utiliser des outputstream sur une Ti...


Utilise la classe moka.io.Graph qui est essentiellement un mapping des fonctions de Graph.h ou l'interopérabilité (permet de faire presque tout ce que l'on fait en C en Moka et essentiel à l'heure actuelle pour utiliser les fonction de vat.h - si qqn est intéressé à réimplémenter moka.io.File avec les fonctions de vat.h à la place de stdio.h, qu'il ne se gêne pas ... je devrai le faire un jour - parce qu'à d'autres endroits de l'API je l'utilise anyway) :

native.DrawLine ( 0, 0, 15, 15 , A_NORMAL );

Et pour créer un fichier ? Une fois j'avais utilisé fopen, fread.... pour faire de la compression de fichier et c'était vraiment lent... alors qu'il est très simple d'écrire directement dans la mémoire. Sans pointeur, je ne demande bien comment faire....
hibOu :
Donc le java me parait finalement assez inapproprié. Je pense que de l'objet pour la Ti devrai plus ressembler à du C++.

Moka est assez proche de ce que serait une implémentation minimale du C++, sans la surcharge des opérateurs et avec un look-and-feel Java. Il est beaucoup plus léger que ces deux langages (mais moins puissant cependant). Je ne vois pas pourquoi un C++ 'light' serait nécessairement plus adapté aux TI68K que le Moka.

Évidemment, tout le monde a des goûts différents et le C++ est un langage très répendu. Je serais le premier à être content de voir un compilateur C++ viable apparaître pour les TI, mais je serais surpris qu'il soit moins lourd que Moka (là je ne parle pas de l'API, juste du langage - les programmes en C++ utilisent beaucoup de fonctions des libs standards du C, ce qui plus performant que de programmer en objet).
S'il implémente des features comme du polymorphisme pur à 100 % (i.e. que la signature du message est déterminé en runtime), alors il génèrera nécessairement des progs plus gros et moins rapides.
c clair, mais je trouve que c'est tout l'interet du langage objet

124

hibOu :
en fait, j'appelle plutot cela de la surcharge. Mais on peut aussi appeler ca du polymorphisme (ad-hoc).
En fait, je sais plus trop comment s'appelle la fonctionnalité suivante :
Object s = new String("blabla");
System.out.println(s); //appelera println(String) et non println(Object)

Et ça je trouve que c'est l'essentiel d'un langage Objet. Sans ça, je ne trouve que le langage ne devient qu'il simple surcouche syntaxique au C.

Fonction virtuelle ? En tout cas ça reste toujours dans le genre surcouche syntaxique... (y a juste un pointeur vers la virtual function table dans chaque instance de la classe)

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

125

Pollux
:
hibOu :
en fait, j'appelle plutot cela de la surcharge. Mais on peut aussi appeler ca du polymorphisme (ad-hoc).
En fait, je sais plus trop comment s'appelle la fonctionnalité suivante :
Object s = new String("blabla");
System.out.println(s); //appelera println(String) et non println(Object)

Et ça je trouve que c'est l'essentiel d'un langage Objet. Sans ça, je ne trouve que le langage ne devient qu'il simple surcouche syntaxique au C.

Fonction virtuelle ? En tout cas ça reste toujours dans le genre surcouche syntaxique... (y a juste un pointeur vers la virtual function table dans chaque instance de la classe)

je crois que ca s'appelle "lien tardif".
Mais cela ne reste pas syntaxique puisqu'il y a du code de rajouté.
le polymorphisme ad-hoc n'est que syntaxique car :
print(String);
print(int);

sera transformé en :
print_String(String);
print_int(int);

Pour le lien tardif, il faut ajouter le code de l'appel de cette "virtual function table"

126

[cite]hibOu :
en fait, j'appelle plutot cela de la surcharge. Mais on peut aussi appeler ca du polymorphisme (ad-hoc).
En fait, je sais plus trop comment s'appelle la fonctionnalité suivante :
Object s = new String("blabla");
System.out.println(s); //appelera println(String) et non println(Object)


En fait, c'est du polymorphisme, mais cela suppose que le compilateur génère la signature en runtime (hé, c'est une String pas un Object !), car il n'a pas idée au moment de la compilation de la vrai nature de l'objet. C'est plus lent par contre.
hibOu :
Et ça je trouve que c'est l'essentiel d'un langage Objet.
Sans ça, je ne trouve que le langage ne devient qu'il simple surcouche syntaxique au C.


Tous les langages objets font certains compromis au paradigme, la majorité des langages typés entre autres ...

En java, ce que retourne la méthode ne fait pas partie de la signature, on ne peut pas avoir

int i = vec.get();
String = vec.get();


Également, dans un langage OO non typé (par exemple smalltalk ou encore objective c - qui supporte le typé ou non), un objet peut recevoir n'importe quel message et une exception n'est soulevée qu'à l'exécution s'il n'y a pas de méthode qui y correspond. En plus, un langage qui respecte totalement le paradigme OO ne devrait jamais permettre d'attributs publiques, et même empêcher les sous classes d'accéder aux attributs sans passer par des méthodes.

Moi, j'aimes les compromis des langages typés et, bien que je trouve dommage que Moka ne supporte pas le type de polymorphisme dont tu parlais, je crois que c'était essentiel pour avoir quelque chose de viable sur calculatrice.
hibOu :
Et pour créer un fichier ? Une fois j'avais utilisé fopen, fread.... pour faire de la compression de fichier et c'était vraiment lent... alors qu'il est très simple d'écrire directement dans la mémoire. Sans pointeur, je ne demande bien comment faire....


Besoin de pointeurs ? Moka ne retourne pas d'erreur de syntaxe lorsqu'on les utilises :
	private static char[] returnToken (char[] str, char[] buf) {
		//TAB, NL, FF, CR, SPACE
    	char[] delim = {9, 10, 12, 13, 32};
    	int len = native.strlen(str);
    	int end;
    	int i;
    	int n;
    	char* pos = str;

		while (*pos != '\0') {
			for (i = 0; i < 5; i++) {
				if (*pos == delim[i]) {
					break;
				}
			}

			if (i == 5) {
				break;
			}

			pos ++;
		}
		
		str = pos;
		
		while (*pos != '\0') {
			for (i = 0; i < 5; i++) {
				if (*pos == delim[i]) {
					break;
				}
			}

			if (i < 5) {
				break;
			}

			pos ++;
		}

		end = (int)(pos - str) ;
		native.memcpy(buf, str, end);

		buf[end] = '\0';

    	return pos;
	}


Pour le reste (les fonctions de vat.h) tu mets tout dans un bloc ou une méthode native et tu fais comme en C...
hibOu :
Pour le lien tardif, il faut ajouter le code de l'appel de cette "virtual function table"

C'est dynamic binding en anglais smile Je n'en savais pas la traduction, j'avais traduit ça 'résolution dynamique des méthodes'. Moka fait du dynamic binding, sans ça l'exemple avec les objets qui interfacent Captioned ne fonctionnerais pas ...

Pour :
Object s = new String("blabla"); 
System.out.println(s); //appelera println(String) et non println(Object) 


Tu peux toujours faire :

Object s = new String("blabla"); 

s.print(); //Pour cela, il faut que la superclasse ait une méthode print


(Dans ce cas println(String) et non println(Object) ont le même effet anyway)

Je sais que c'est moins plaisant que du polymorphisme pur pour les méthodes ... Mais le gain en vitesse est incroyable. J'ai imaginé quelques algos pour en faire du pur et dur, et ça ne me paraissait pas gagnant ...

Pour le lien tardif, il faut ajouter le code de l'appel de cette "virtual function table"

Là, j'en connais certains qui me critiquerais si j'implémentais ce truc ...

127

Quesoft :
Moi, j'aimes les compromis des langages typés et, bien que je trouve dommage que Moka ne supporte pas le type de polymorphisme dont tu parlais, je crois que c'était essentiel pour avoir quelque chose de viable sur calculatrice.
hibOu :
Et pour créer un fichier ? Une fois j'avais utilisé fopen, fread.... pour faire de la compression de fichier et c'était vraiment lent... alors qu'il est très simple d'écrire directement dans la mémoire. Sans pointeur, je ne demande bien comment faire....


Besoin de pointeurs ? Moka ne retourne pas d'erreur de syntaxe lorsqu'on les utilises :
	private static char[] returnToken (char[] str, char[] buf) {
		//TAB, NL, FF, CR, SPACE
    	char[] delim = {9, 10, 12, 13, 32};
    	int len = native.strlen(str);
    	int end;
    	int i;
    	int n;
    	char* pos = str;

		while (*pos != '\0') {
			for (i = 0; i < 5; i++) {
				if (*pos == delim[i]) {
					break;
				}
			}

			if (i == 5) {
				break;
			}

			pos ++;
		}
		
		str = pos;
		
		while (*pos != '\0') {
			for (i = 0; i < 5; i++) {
				if (*pos == delim[i]) {
					break;
				}
			}

			if (i < 5) {
				break;
			}

			pos ++;
		}

		end = (int)(pos - str) ;
		native.memcpy(buf, str, end);

		buf[end] = '\0';

    	return pos;
	}


Pour le reste (les fonctions de vat.h) tu mets tout dans un bloc ou une méthode native et tu fais comme en C...

ha, il y a des pointeurs.
Ca ressemble déjà moins au java. D'ailleurs, ca cause pas des pb lors de la génération de la javadoc ?

Là, j'en connais certains qui me critiquerais si j'implémentais ce truc ...
il faudrait alors répondre à ces personnes qu'elles devraient faire du C ! tongue

Je comprend mieux ton projet. A mon avis tu devrais cependant éviter une trop grande comparaison à java. Il faudrait juste énoncé le fait que tu t'en inspires.

Je vais p-ê me mettre un peu à moka alors, pour essayer smile

128

Et si tu faisais comme en C++, c'est-à-dire qu'il faut marquer explicitement les fonctions virtual pour avoir du polymorphisme dynamique?
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

129

hibOu :
ha, il y a des pointeurs.
Ca ressemble déjà moins au java. D'ailleurs, ca cause pas des pb lors de la génération de la javadoc ?

Oui, ça cause des problèmes. Pour générer la javadoc, il faut respecter les specs Java (pas de pointeurs, pas de blocs native, etc.).
hibOu :
il faudrait alors répondre à ces personnes qu'elles devraient faire du C ! tongue

grin Oui, mais je voulais un langage utilisable en pratique, alors c'est pourquoi j'ai fais ces choix là ...
hibOu :
Je comprend mieux ton projet. A mon avis tu devrais cependant éviter une trop grande comparaison à java. Il faudrait juste énoncé le fait que tu t'en inspires.

En effet. Cependant, si quelqu'un résiste à utiliser les extensions, programmer en Moka est très similaire à programmer en Java (même si l'API de Moka est radicalement différent).
hibOu :
Je vais p-ê me mettre un peu à moka alors, pour essayer smile

Cool smile
Kevin Kofler :
Et si tu faisais comme en C++, c'est-à-dire qu'il faut marquer explicitement les fonctions virtual pour avoir du polymorphisme dynamique?

Effectivement, ça serait une solution. Cependant, il est toujours possible - et c'est plus OO à mon avis - d'invoquer un méthode au lieu de passer l'objet en paramètre. Exemple :

Personne p = new Personne("Nom personne");
Personne g = new GrandPere("Nom GP");

//Au lieu de faire :

MaClasse.afficher(g); //Qui est surchargée pour traiter et les GP et les personnes

//On peut faire :

g.afficher(); // Qui est une méthode de la superclasse Personne overridée par la classe GrandPere


Sinon, il y a les instanceof, je répète que je sais que c'est plus plate que de disposer d'un réel polymorphisme dynamique pour les méthodes ...

ps
En C++, une méthode non-virtuelle peut-elle être overridée ? Il me s'emblait que non ...

130

Si si on peut redéfinir une méthode non virtuelle ^^

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

131

Pollux :
Si si on peut redéfinir une méthode non virtuelle ^^

Ok, j'ai jamais fait de C++ ...

132

Honnêtement si tu veux que Moka soit plus utile pour faire des gros projets, tu devrais piquer quelques idées au C++ : par exemple, le fait de pouvoir libérer automatiquement un objet dès qu'il n'est plus visible serait très utile et éviterait que les programmes Moka aient d'énormes leaks de mémoire... (mais évidemment ça reste délicat, il faut employer des références dans certains cas, etc...)

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

133

Pollux :
Honnêtement si tu veux que Moka soit plus utile pour faire des gros projets, tu devrais piquer quelques idées au C++ : par exemple, le fait de pouvoir libérer automatiquement un objet dès qu'il n'est plus visible serait très utile et éviterait que les programmes Moka aient d'énormes leaks de mémoire... (mais évidemment ça reste délicat, il faut employer des références dans certains cas, etc...)

Je ne pensais pas que le C++ faisait du garbage collecting ...

Est-ce que tu parles de :

TTruc t;


vs

TTruc *t = new TTruc();


?

134

Le C++ ne fait pas de GC, il fait des objets automatiques (locaux):
{
Truc t;
...
}

et hop, ici, l'objet t sort du scope, donc il est détruit automatiquement.
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

135

Désolé, j'ai pas été clair, par "visible" je voulais dire "dans la portée de la déclaration" (et pas "accessible à partir d'un objet" comme dans le cas de la garbage collection) ; si je fais :
char *t = "world";
{
  string s = (string)"hello "+t;
  cout << s;
}


ça se traduirait en C par :
char *t = "world";
{
  string s,hello;
  String::new_from_charptr(&hello,"hello ");
  String::concat_with_charptr(&s,&hello,t);
  String::delete(&hello);
  ostream::append_string(&cout,&s);
  String::delete(&s);
}

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

136

Sachant que MOKA genere du C, suivant comment il définit les variables de type "objets" si ils sont défini localement a une procedure, il seront détruit comme le C le fait. Apres ça dépend comment il représente les objets.


avatar
Proud to be CAKE©®™


GCC4TI importe qui a problème en Autriche, pour l'UE plus et une encore de correspours nucléaire, ce n'est pas ytre d'instérier. L'état très même contraire, toujours reconstruire un pouvoir une choyer d'aucrée de compris le plus mite de genre, ce n'est pas moins)
Stalin est l'élection de la langie.

137

Godzil :
Sachant que MOKA genere du C, suivant comment il définit les variables de type "objets" si ils sont défini localement a une procedure, il seront détruit comme le C le fait. Apres ça dépend comment il représente les objets.

En Moka, comme en Java, une variable objet est une référence vers l'objet, et non l'objet. C'est comme avoir un pointeur vers zone mémoire. Il serait pas trop complexe d'implémenter des objets avec un scope limité :

//Je déclare un Object o avec un scope déterminé, ce serait traduit par quelque chose de semblable :
TObject mem; //Mon emplacement mémoire
TObject *o = &mem;//J'ai une référence vers l'objet - transparent pour l'utilisateur.

//Quand on initialise o - o = new Object()
initTObject(o); //Fonction fictive qui initialiserait l'objet 


Reste que l'API ne s'attend pas à avoir des objets à scope restreint et que cela pourrait poser des problèmes...
Pollux :
Si si on peut redéfinir une méthode non virtuelle ^^

Je m'était mal exprimé en parlant d'override. J'ai ouvert mon livre de C++ et je me suis rendu compte que les méthodes en Moka (celles qui ne sont pas statiques évidemment) sont équivalentes aux fonctions virtuelles en C++. La différente est la suivante :

En C++, si j'ai une classe qui définit une méthode m (qui n'est pas virtuelle) et que sa sous classe l'override, ceci se produit :
MaClasse *o = new MaSousClasse(); //Pour le compilateur, o est un MaClasse, alors qu'en runtime, o se révèle être un MaSousClasse.

o.m(); //Lien statique : la méthode de MaClasse est invoquée.


En moka :
MaClasse o = new MaSousClasse(); //Pour le compilateur, o est un MaClasse, alors qu'en runtime, o se révèle être un MaSousClasse.

o.m(); //Lien dynamique: la méthode de MaSousClasse est invoquée.


Pour pouvoir exploiter cette forme de polymorphisme en C++, m devra être définie comme virtual ... et invoquée comme ça si je ne fais pas erreur : o->m().

J'ai sûrement des erreur de syntaxe en C++, mais vous comprendrez ce que je veux dire j'en suis sûr ...

138

Donc il y a déjà du polymorphisme dynamique, comme en Java. C'est juste la surcharge qui ne le gère pas, et là, franchement, je ne suis pas sûr de quelle manière ce soit géré en C++ et en Java. Je ne pense pas qu'il y ait un runtime dispatch pour le surchargement en C++, donc je pense que c'est comme en Moka.
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

139

Kevin Kofler :
Donc il y a déjà du polymorphisme dynamique, comme en Java. C'est juste la surcharge qui ne le gère pas, et là, franchement, je ne suis pas sûr de quelle manière ce soit géré en C++ et en Java.

Un runtime dispatch (je crois qu'Objective C fait ça), j'ai peur que ce soit vraiment peu performant. En Moka, un appel de méthode ce fait comme ça :

//o.maMethode() est traduit :
o->maMethode_(o);


Vous comprendrez que le membre maMethode_ pointe vers une fonction. En théoriePour supporter le runtime dispatch il faudrait que je fasse quelque chose de semblable à ce que je fais avec les interfaces :

//o.maMethode() est traduit :
MonInterface_maMethode_(o);


La fonction MonInterface_maMethode_() contient du code pour retrouver la bonne fonction p/r à la classe de o. C'est moins rapide que dans le premier cas par contre (mais pas trop lent car les pointeurs sont stoké en mémoire et retrouvés avec un index que l'objet connait).
Kevin Kofler :
Je ne pense pas qu'il y ait un runtime dispatch pour le surchargement en C++, donc je pense que c'est comme en Moka.


Est-ce qu'en C++ le code suivant se comporterais comme en Moka :
Object s = new String("blabla"); 
System.out->println(s); //appelera println(Object) au lieu de println(Object) 


Comme je vous avais dit, Moka est vraiment OO, même s'il est limité ...

140

En fait, je me suis complètement mélangé les idées.....
en fait moka supporte bien ce à quoi je pensais :
Object s = new String();
s.clone(); // appel de String.clone() et non Object.clone()

Quesoft
:
Kevin Kofler :
Donc il y a déjà du polymorphisme dynamique, comme en Java. C'est juste la surcharge qui ne le gère pas, et là, franchement, je ne suis pas sûr de quelle manière ce soit géré en C++ et en Java.

Un runtime dispatch (je crois qu'Objective C fait ça), j'ai peur que ce soit vraiment peu performant. En Moka, un appel de méthode ce fait comme ça :

//o.maMethode() est traduit :
o->maMethode_(o);


Vous comprendrez que le membre maMethode_ pointe vers une fonction. En théoriePour supporter le runtime dispatch il faudrait que je fasse quelque chose de semblable à ce que je fais avec les interfaces :

//o.maMethode() est traduit :
MonInterface_maMethode_(o);


La fonction MonInterface_maMethode_() contient du code pour retrouver la bonne fonction p/r à la classe de o. C'est moins rapide que dans le premier cas par contre (mais pas trop lent car les pointeurs sont stoké en mémoire et retrouvés avec un index que l'objet connait).

A mon avis, y'a plus simple que de faire une recherche.
Faudrait créer des structure en global :
struct st_Fonctions_Objects {
    Object * (*clone) (Object *) = &clone_Objects;
} Fonctions_Objects;

struct st_Fonctions_ClasseMachin {  //classe machin hérite de Object
    Object * (*clone) (Object *) = &clone_Objects;  //si il n'y a pas de redéfinition
    void ( * fonction_truc) (ClasseMahin *) = &fonction_truc_ClasseMachin;
} Fonctions_ClasseMachin;

et après tous les appels se feront par :
ClasseMachin c = new ClasseMachin();
c.clone();
traduit en :
ClasseMachin * c = malloc(....);
Fonctions_ClasseMachin->clone(c);

141

je viens de tester ca en java 1.4 :

public class test {

	public static void main(String[] args) {
		test t = new test();
		Object o = new String ();
		
		t.f(new String());
		t.f(o);
	}
	
	void f(Object o) {
		System.out.println("obj");
	}
	
	void f(String s) {
		System.out.println("str");
	}
}


et ca sort :

str
obj

142

hibOu :
et ca sort :

[pre]
str
obj

Grand dieu !

Je dois le tester, je n’y crois pas !

Si c’est vrai (je ne remet pas ta parole en doute, donc ça doit l’être), Java génère, comme Moka, la signature à la compilation. C’est triste, parce que c’est moins pur comme polymorphisme …

Anyway, en envoyant un message à l’objet (au lieu d’envoyer l’objet comme paramètre d’une méthode) on peut exploiter le polymorphisme, malgré cette limitation …
hibOu :
A mon avis, y'a plus simple que de faire une recherche.
Faudrait créer des structure en global :
struct st_Fonctions_Objects {
    Object * (*clone) (Object *) = &clone_Objects;
} Fonctions_Objects;

struct st_Fonctions_ClasseMachin {  //classe machin hérite de Object
    Object * (*clone) (Object *) = &clone_Objects;  //si il n'y a pas de redéfinition
    void ( * fonction_truc) (ClasseMahin *) = &fonction_truc_ClasseMachin;
} Fonctions_ClasseMachin;

et après tous les appels se feront par :
ClasseMachin c = new ClasseMachin();
c.clone();
traduit en :
ClasseMachin * c = malloc(....);
Fonctions_ClasseMachin->clone(c);


Un mécanisme similaire est déjà en place, lorsque le compilateur connaît la classe de l’objet :

ClasseMachin c = new ClasseMachin();
c.clone();
traduit en :
TClasseMachin * c = TClasseMachin_(); // où TClasseMachin est le type de la structure et TClasseMachin_() un constructeur qui retourne un ClasseMachin alloué et initialisé
c->clone_(c);


Si ClasseMachin implémente une interface, et que tout ce que le compilateur sait de l’objet c est qu’il implémente cette interface, il ne saura pas quelle méthode appeler ni même où se trouvera en mémoire l’adresse de la fonction :

typedef struct {
//Methode 1
//Methode de MonInterface
} TClasseA;
typedef struct {
//Methode 1
//Méthode 2
//Methode de MonInterface
} TClasseMachin;


Comme on peut le constater, ClasseA et ClasseMachin implémentant toutes deux la méthode de l’interface, il est légitime de coder :

ClasseA a = new  ClasseA();
ClasseMachin c= new  ClasseMachin ();
MonInterface iA = a;
MonInterface iC = c;

a.methodeInter(); //Ok, je sais où est mon pointeur (pos 2)
c.methodeInter(); //Ok, je sais où est mon pointeur (pos 3)

iA.methodeInter();//Où est le pointeur ? (dépend du type de iA en cours d’exécution)


C’est pour cela que j’ai implémenté la recherche pour les cas d'interface (qui est pas trop lente quand même).

143

Quesoft :
ClasseA a = new  ClasseA();
ClasseMachin c= new  ClasseMachin ();
MonInterface iA = a;
MonInterface iC = c;

a.methodeInter(); //Ok, je sais où est mon pointeur (pos 2)
c.methodeInter(); //Ok, je sais où est mon pointeur (pos 3)

iA.methodeInter();//Où est le pointeur ? (dépend du type de iA en cours d’exécution)


C’est pour cela que j’ai implémenté la recherche pour les cas d'interface (qui est pas trop lente quand même).

mince, j'ai encore raconter des betises.....
En fait je l'ai codé dans un pseudo-assembleur, donc je dois avoir un peu de mal à la translater au C.

Alors:
y'a toujours les structures globales :
struct st_Fonctions_Objects {
    Object * (*clone) (Object *) = &clone_Objects;
    char * (*toString) (Object *) = &toString_Objects;
} Fonctions_Objects;

struct st_Fonctions_ClasseMachin {  //classe machin hérite de Object
    Object * (*clone) (Object *) = &clone_Objects;  //si il n'y a pas de redéfinition
    char * (*toString) (Object *) = &toString_ClasseMachin; //il y a une redéfinition
    void ( * fonction_truc) (ClasseMahin *) = &fonction_truc_ClasseMachin;
} Fonctions_ClasseMachin;

NB : l'odre des fonctions est importantes : si clone est la 1ère fonction et toString la 2ème dans Object, clone doit alors êtres est la 1ère fonction et toString la 2ème dans ClasseMachin.

la définition de la classe :
struct ClasseMachin {
   st_Fonction_ClasseMachin * tab_fonctions;
....attributs...
}

et après tous les appels se feront par :
ClasseMachin c = new ClasseMachin();
....
c.clone();
traduit en :
ClasseMachin * c = malloc(....);
c->tab_fonctions = &Fonctions_ClasseMachin;
....
c->tab_fonctions->clone(c);

et donc :
Objet c = new ClasseMachin();
....
c.clone();
se traduit aussi par
Objet * c = malloc(....);
c->tab_fonctions = &Fonctions_Objet;
....
c->tab_fonctions->clone(c);

Note que ici Objet peut être une interface.
Et aussi, l'intanceof pourra se résumer à la comparaison des "tab_fonction"

144

hibOu :
Note que ici Objet peut être une interface.
Et aussi, l'intanceof pourra se résumer à la comparaison des "tab_fonction"

Je comprend maintenant mieux ton idée. Cela permettrait d'économiser un peu d'espace p/r à mon implémentation.

145

Je reprends le code de hiBOu

public class test { 
 
	public static void main(String[] args) { 
		test t = new test(); 
		Object o = new String (); 
		 
		t.f(new String()); 
		t.f(o); 
	} 
	 
	void f(Object o) { 
		System.out.println("obj"); 
	} 
	 
	void f(String s) { 
		System.out.println("str"); 
	} 
} 


Notez que je vois la programmation avec des yeux un peu naifs, n'ayant aucune notion de ce dont vous parlez.

N'est il pas normal que le type de l'objet soit imposé par sa déclaration?
En écrivant
Object o = new String ();
vous créez un java.lang.Object en l'initialisant avec un java.lang.String

String hérite de Object, donc l'Object créé est initialisé avec l'héritage du new String() vu comme un Object
Mais il est déclaré en tant qu' Object. Donc il en ressort un Object, qui appelle la méthode demandant un Object.

normal nan?

146

hibOu :
Note que ici Objet peut être une interface.
Et aussi, l'intanceof pourra se résumer à la comparaison des "tab_fonction"

On a le même problème avec les interfaces cependant :

ClasseA a = new  ClasseA();
ClasseMachin c= new  ClasseMachin ();
MonInterface iA = a;
MonInterface iC = c;

iA.methodeInter();//Où est le pointeur ?


Le copilateur traduirait :
iA->tab_fonctions->methodeInter(iA);

tab_fonction pointe au bon endroit (i.e. la table des fonctions de ClasseA) cependant, le compilateur la voit comme une structure st_Fonctions_MonInteface. Ça cause un problème si, par exemple, la classe ClasseA définit d'autres méthodes avant celle de l'interface, car ce seront celles-ci qui seront exécutés.


Pour ton information, instanceof est implémenté de façon similaire -côté algorithme- à ce que tu proposes:

BOOL instanceof ( TObject * object, TObject * prototype ) { 
	BOOL result = FALSE ; 
	while ( ( object != NULL ) && ! result ) { //Évidemment, le membre super de Object, superclasse de toutes les autres classes est NULL
		if ( object -> class_id == prototype->class_id ) { //Chaque classe a un id unique attribué séquentiellement
			result = TRUE ; 
		} 
		object = object -> super ; //ici, on a un pointeur vers un 'prototype' de la superclasse de l'objet en question
	} 
	return result ; 
}


Ouch, je pense qu'il est possible d'améliorer un peu l'algo (qui doit datter de Moka 1.0a), dans la prochaine version, je vais changer pour :
BOOL instanceof ( TObject * object, TObject * prototype ) { 
	while ( object ) { 
		if ( object -> class_id == prototype -> class_id ) { 
			return TRUE ; 
		} 
		object = object -> super ;
	} 
	return FALSE ; 
}


Ça changera pas grand chose, mais bon ...

147

Squalyl: oui dans un environement compilé c'est ce qui se passera, dans un environement interpreté, on peut savoir quel est le type reel de o
avatar
Proud to be CAKE©®™


GCC4TI importe qui a problème en Autriche, pour l'UE plus et une encore de correspours nucléaire, ce n'est pas ytre d'instérier. L'état très même contraire, toujours reconstruire un pouvoir une choyer d'aucrée de compris le plus mite de genre, ce n'est pas moins)
Stalin est l'élection de la langie.

148

Oui, mais le polymorphisme aurait pu être poussé plus loin et considérer le vrai type de o (c'est-à-dire String) pour savoir quelle routine appeler.
Cela dit, je ne sais pas si ça ne risquerait pas de poser problème...
avatar
« Quand le dernier arbre sera abattu, la dernière rivière empoisonnée, le dernier poisson capturé, alors vous découvrirez que l'argent ne se mange pas. »

149

squalyl^2 :
String hérite de Object, donc l'Object créé est initialisé avec l'héritage du new String() vu comme un Object
Mais il est déclaré en tant qu' Object. Donc il en ressort un Object, qui appelle la méthode demandant un Object.

normal nan?

Une String est un Object. C'est absolument vrai et tout à fait normal qu'il puisse être traité de la même manière que n'importe quel autre Object (c'est ça le polymorphisme, entre autres). Cependant, il reste une String, et si une méthode existe en deux versions, une qui peut traiter des String et une qui peut traiter des Objects, je trouverait plus normal que celle qui peut traiter des String soit appelée (car la nature de l'objet qui est passé en paramètre est une String).

Cependant, en Moka (et en Java on dirait), la signature de la méthode est générée à la compilation, donc :

-pour t.f(new String());-
nom = f
arguments = String

-pour t.f(o);-
nom = f
arguments = Object

C'est pas dramatique, ça n'empêche pas d'exploiter le polymorphisme, comme je le disais avant même de savoir que Java avait le même comportement que Moka ...

150

Godzil :
Squalyl: oui dans un environement compilé c'est ce qui se passera, dans un environement interpreté, on peut savoir quel est le type reel de o

En théorie, en compilé aussi, mais c'est lent :

En compile time on peut faire une partie de la 'job' :
- Sortir toutes les méthodes susceptibles d'êtres appelées (même nombre d'argument, entre autres + on élimines celles qui ont des paramètres dont les classes ne correspondent pas à une superclasse de l'argument passé, etc.)

En run time :
- Vérifier, pour chaque argument qui n'est pas un type primitif, la nature exacte de l'objet.
- Faire un 'best match' avec les méthode compatibles (i.e. si l'argument est une String, prendre la méthode qui accepte des Strings avant celle qui accepte des Objects).
- Invoquer la méthode.

Très lent p/r à

En compile time :
- Sortir toutes les méthodes susceptibles d'êtres appelées (même nombre d'argument, entre autres + on élimines celles qui ont des paramètres dont les classes ne correspondent pas à une superclasse de l'argument passé, etc.)
- Faire un 'best match' - là on regarde le type déclaré de l'objet - avec les méthode compatibles (i.e. si l'argument est une String, prendre la méthode qui accepte des Strings avant celle qui accepte des Objects).

En run time :
- Invoquer la méthode.

Moka utilise la deuxième méthode ...