[Java] Find The Bug !

Voici, comme promis, la réponse.

L’erreur se trouve, bien évidemment dans le test d’egalité

Le problème vient de getNom(). Les deux String sont en effet deux objets différents, donc placés à des endroits différents dans la mémoire . Or, en Java, on ne fait que manipuler des références d’objets, donc “tmp1.getNom() == tmp2.getNom()” revient à comparer les emplacements mémoire des deux Strings, forcément différents.

Ceci ne s’applique pas aux types int, float, double etc …, on doit utiliser “==” (ce ne sont pas des classes). Par contre, si on utilise les classes les encapsulant (Int, Float, Double), alors, il faut de nouveau utiliser la méthode “equals(java.lang.Object object)”

Le test à écrire est

Humm oui … on compare la valeur des références et non pas les vraie string … mais alors ? Pkoi moi j’ai faux ?
:stuck_out_tongue:

java version « 1.5.0 »
Java™ 2 Runtime Environment, Standard Edition (build 1.5.0-b64)
Java HotSpot™ Client VM (build 1.5.0-b64, mixed mode)

[code]            liste1.add(new Personne(« toto »,2));
           liste1.add(new Personne(« toto »,5));
           liste1.add(new Personne(« tata »,3));

           liste2.add(new Personne(« tutu »,1));
           liste2.add(new Personne(« titi »,2));
           liste2.add(new Personne(new String(« tata »),3));[/code]

me donne

Les deux personnes sont differentes
Les deux personnes sont differentes
Les deux personnes sont differentes

par contre

[code]            liste1.add(new Personne(« toto »,2));
           liste1.add(new Personne(« toto »,5));
           liste1.add(new Personne(« tata »,3));

           liste2.add(new Personne(« tutu »,1));
           liste2.add(new Personne(« titi »,2));
           liste2.add(new Personne(« tata »,3));[/code]

me donne

Les deux personnes sont differentes
Les deux personnes sont differentes
Les deux personnes sont identiques

Je vous laisse faire votre propre idée…

Pour le truc de faden, il faudra que j’essaie chez moi, mais à tous les coups c’est la nouvelle version qui cause ça.

La méthode la plus propre est quand même de surcharger la méthode equals dans la class Personne et de ne faire qu’un seul test dans la boucle.

public boolean equals(Object object) {    if(! object instanceof Personne)         return false;        Personne personne = (Personne)object;    return this.getNom().equals(personne.getNom()) && this.getDossard() == personne.getDossard();   }

[quote name=‘LeBaronNoir’ date=’ 17 Nov 2004, 22:16’]Pour le truc de faden, il faudra que j’essaie chez moi, mais à tous les coups c’est la nouvelle version qui cause ça.
[right][post=“304183”]<{POST_SNAPBACK}>[/post][/right][/quote]

Pour les nouveautés de 1.5, un excellent article.

[quote name=‹ ZGoblin › date=’ 17 Nov 2004, 22:19’]La méthode la plus propre est quand même de surcharger la méthode equals dans la class Personne et de ne faire qu’un seul test dans la boucle.

[code]public boolean equals(Object object) {
if(! object instanceof Personne)
return false;

Personne personne = (Personne)object;
return this.getNom().equals(personne.getNom()) && this.getDossard() == personne.getDossard();

}[/code]
[right][post=« 304185 »]<{POST_SNAPBACK}>[/post][/right][/quote]
ahahah tu trouves ça propre :stuck_out_tongue: //// J’aimerais pas avoir à contrôler ton code :stuck_out_tongue:

edit : d’ailleurs, le && est prioritaire sur le == non ?

Waip, sans doute une nouvelle version. C’est le problème de Java. Le fait qu’il n’est pas normalisé fait qu’entre deux version, des trucs deviennent obsolètes, et ca peut changer de comportement …

Donc bug valable pour versions <= Java 1.4.2

Bon, pendant que le serveur redémarre.

Java n’est pas complètement objet, contrairement à Smalltalk, Simula, Ruby, Eiffel, etc. Il y a mélange entre des « types intrinsèques » et des classes. « String » est une classe mais « int » est un type. C’est sans doute un reste inconscient de Stroustrup dans le cerveau de Gosling :stuck_out_tongue:

Par ailleurs, et entre autre à cause de la complexité sous-jascente à manipuler à la fois des types et des classes, java n’implémente pas complètement la surcharge des opérateurs. Là où la plupart des autres langages objets surchargent le test d’égalité ‹ == › quand celà a un sens (classes représentant des chaînes, tableaux, couples, complexes, etc.), Java réserve ce test à la comparaison des valeurs des variables typées et au test d’identité des instances de classes.

Dans le monde objet, il s’agit d’une erreur sémantique et donc logique: dans le cas variable typée ‹ == › est un test d’égalité, et dans le cas instance classée c’est un test d’identité.

La surcharge de ce test simple (attention, la surcharge systématique des opérateurs n’est pas nécessairement une bonne chose non plus) éviterait bien des erreurs et éliminerait peut être un obstacle qui empêche de se débarrasser complètement d’une verrue telle que les types.

Pour simplifier.

Là où le manque de logique est encore plus choquant c’est que la surcharge d’opérateur n’existe pas en Java, sauf pour l’opérateur +, qui permet de concatener des String! Cette concaténation n’en est même pas une, car les String sont immutables (une autre classe, Stringbuffer, représente les chaînes de charactères mutables).

Beurk quoi.

En plus c’est pas garanti que le resultat soit different. Toute JVM qui vaut sont pesant de cacahouette va repondre « identique » parcequ’elle aura detecte que les strings sont identiques et mis les deux au meme endroit dans la memoire. D’ou les difference de comportement entre les versions que vous voyez.

Sinon tiens pour rigoler pourquoi java c’est pas top je vous met le meme code en C#:

[code]public class Personne {
private string nom;
private int dossard;

public Personne(sring nom,int dossard){
		this.nom = nom;
		this.dossard = dossard;
}

public String Nom {
   get{ return nom; }
}
public int Dossard {
   get { return dossard; }
}

}

public class Comparateur {
static void Main(string[] args){
List liste1 = new List();
List liste1 = new List();

		liste1.Add(new Personne("toto",2));
		liste1.Add(new Personne("toto",5));
		liste1.Add(new Personne("tata",3));

		liste2.Add(new Personne("tutu",1));
		liste2.Add(new Personne("titi",2));
		liste2.Add(new Personne("tata",3));

		foreach(Personne p1 in liste1) {
		   foreach(Personne p2 in liste2) {
			   if(p1.Nom == p2.Nom && p1.Dossard == p2.Dossard) {
				   Console.WriteLine("Tout pareil");
			   } else {
				   Console.WriteLine("Tout pas pareil");
			   }
		   }
		}   
 }

}[/code]

Bon je sais qu’on compare pas exactement la meme chose, la je compare toute la liste1 avec toute la liste 2 :stuck_out_tongue: Sinon suffit de remplacer foreach par un for tout simple et de faire liste1[i]. Ha ouai, le probleme ne se pose pas avec C#, string etant un value type. Bon c’est mega hors sujet et laid de poster ca :stuck_out_tongue: Mais j’ai aussi donne la reponse B).

Sinon oui la surcharge d’operateur existe mais c’est plus sale :P. Voir page d’apres :stuck_out_tongue:

Vala…
Et la, moi je dis, le C# ca roxe, pasqu’on peux surcharger l’opérateur == …
Du coup, bah, j’ai pas vu le bug…

Heu, l’autre, he, y me grille, et il frime avec ses generics :stuck_out_tongue: ! …
Glop : Note c’est pas le fait que ca soit un ValueType, mais bien que l’opérateur == est surchargé pour les String… (ce qui est soit dit en passant vachement plus interressant :stuck_out_tongue: ).


T'aurai pas oublié des paranthèses par hasard ?

T’aurai pas oublié des paranthèses par hasard ?

[quote name=‹ Tzim › date=’ 17 Nov 2004, 13:30’]Glop : Note c’est pas le fait que ca soit un ValueType, mais bien que l’opérateur == est surchargé pour les String… (ce qui est soit dit en passant vachement plus interressant :stuck_out_tongue: ).
[right][post=« 304199 »]<{POST_SNAPBACK}>[/post][/right][/quote]
C’est pas la question de comment c’est fait, c’est le resultat qui est important. En C# tout est fait pour que string apparaisse comme un value type, immutable.

[quote name=‘Amalsek’ date=’ 17 Nov 2004, 22:34’] if(p1.Nom == p2.Nom && p1.Dossard == p2.Dossard) {

T’aurai pas oublié des paranthèses par hasard ?
[right][post=“304202”]<{POST_SNAPBACK}>[/post][/right][/quote]
Hé non !
C’est la beauté des properties… Plus de getTruc() et setMachins()…

[quote name=‹ Amalsek › date=’ 17 Nov 2004, 13:34’] if(p1.Nom == p2.Nom && p1.Dossard == p2.Dossard) {

T’aurai pas oublié des paranthèses par hasard ?
[right][post=« 304202 »]<{POST_SNAPBACK}>[/post][/right][/quote]
Non. :stuck_out_tongue:

Sinon oui la surcharge d’operateur existe, mais il faut se mefier, c’est super contre intuitif pour les types qui justement sont pas immutable et des value type. C’est a reserver a ces cas la la surcharge d’operateur, sinon on s’en sort pas c’est sale et inconsistant niveau API. Donc dans ce cas la, je dis NON a la surcharge d’operateur :stuck_out_tongue:

En plus c’est pas qu’un peu gallere en Java pour les langues qui ont pas les memes regles minuscules/majuscules que nous, en Turkish I par exemple. Pour faire une comparaison de string il faut pouvoir specifier la « culture » dans laquelle on fait la comparaison. Tout le monde a pas les meme regles d’ordre alphabetique ou d’egalite en case insensitive.

Avec surcharge d’operateur il faut rajouter ca a personne:

public static bool operator ==(Personne left, Personne right) { return (left.Dossard==right.Dossard && string.Compare(left.Nom, right.Nom, false, CultureInfo.InvariantCulture) == 0)); }

Pour faire simple et culture invariante, case insensitive.

Je vais donc installer Mono sur ma Debian et me mettre au C# pour essayer (et faire plus que le survoler 1h comme la dernière fois)

Essaie aussi Ruby (pour Debian) et si tu fais du serveurs applicatifs regarde ce que propose Ruby on Rails. Tu m’en diras des nouvelles. :stuck_out_tongue:

Gnaa la surcharge d’opérateur caypabo… Ca fait du code tout incompréhensible… Franchement…

[quote name=‹ kaneloon › date=’ 17 Nov 2004, 13:50’]Gnaa la surcharge d’opérateur caypabo… Ca fait du code tout incompréhensible… Franchement…
[right][post=« 304219 »]<{POST_SNAPBACK}>[/post][/right][/quote]
Oui, enfin faut jamais dire jamais :stuck_out_tongue: C’est pas beau sur les reference type de base. Sur les value type immutable c’est la logique meme :stuck_out_tongue: et il y a pas que les valeurs de base genre int/float/autre ou ca a un sens de faire du value type immutable. Mais faut pas en mettre partout sinon on comprend plus rien, 100% d’accord, sur un vecteur avec deux valeurs, ca roxor, sur une personne avec un nom et un dossard ca craint :stuck_out_tongue:

[quote name=‹ GloP › date=’ 17 Nov 2004, 22:53’]Oui, enfin faut jamais dire jamais :stuck_out_tongue: C’est pas beau sur les reference type de base. Sur les value type immutable c’est la logique meme :stuck_out_tongue: et il y a pas que les valeurs de base genre int/float/autre ou ca a un sens de faire du value type immutable. Mais faut pas en mettre partout sinon on comprend plus rien, 100% d’accord, sur un vecteur avec deux valeurs, ca roxor, sur une personne avec un nom et un dossard ca craint :stuck_out_tongue:
[right][post=« 304222 »]<{POST_SNAPBACK}>[/post][/right][/quote]

Ben si tu définis 200 types immutables avec opérateur, le pov mec qui relit ton code doit se taper la définition de tous tes types alors qu’avec une fonction de type boolean compareMoiLesValeursDeCePutainDeVecteurAvecCellesDeLAutre(Vecteur putainDeVecteur, Vecteur deLAutre), c’est quand même plus simple à capter… m’enfin bref…

Oui m’enfin bon, en vrai programmation objet (Smalltalk et ceux qui s’en réclament), les opérateurs c’est juste du sucre syntactique qui est remplacé à la compilation par des appels à des vraies méthodes, vu que tout est objet:stuck_out_tongue:

programmation classique => programmation orientée objet
type => classe
variable => instance (objet)
opérateur => méthode
fonction => méthode

Et c’est là que le bas blesse avec Java. Si Smalltalk se comportait pareil alors le compilateur transformerait « == » en Object.isEqual ou en Object.isIdentical selon les classes. Re-beurk. Exactement comme si un programmeur débutant n’avait pas respecté les conventions dans la surcharge de l’opérateur (un des gros défaut que l’on trouve souvent à ce mécanisme).