WTF !! Mais c'est ça qui méritait un journal dénonciateur !!
Je fais rarement des choses dénonciatrices ;) C'est beaucoup plus intéressant de comprendre le processus et l'idée qu'il y a derrière un changement. En l’occurrence, l'auteur de ce changement à pas mal expliqué les choses sur reddit.
Après on peut émettre un avis: le sien. Pour ce changement je comprends parfaitement le rationnel, et je pense que par défaut le comportement actuel est le bon. Il y a plus de monde qui se faisait piéger par la référence gardée sur le buffer original que de gens écrivant des parser sachant ce qu'ils font (et plus de gens intéressés à gagner 8 octets par instance). À l'époque j'avais même du écrire un agent pour essayer d'identifier les substring qui survivaient à plusieurs GC pour auditer une grosse base de code. Ce qui est beaucoup plus discutable c'est que maintenant il soit impossible d'avoir accès à l'ancien comportement et de l'avoir fait dans une mineure.
Mais la leçon la plus intéressante, c'est de voir que ce deuxième changement a été précipité par l'ajout de hash32 qui était une mauvaise réponse au problème.
Quant à leur solution à la problématique d'attaque par collisions elle me laisse un goût amer. Ils ont fortement compliqué l'implémentation de la classe de référence.
Je ne suis pas d'accord avec ça. La réponse de la JEP 180 est pour moi la bonne: corriger la structure de donnée pour offrir une meilleure complexité au pire cas et une performance équivalente au cas moyen.
Ça pallie aux attaques par collision sur les Strings.
Ça gère mieux les fonctions de hash biaisées. Il n'y a pas que String dans la vie, et les fonctions des utilisateurs sont en général une catastrophe (j'inclus les miennes)
Ça permet d'être plus agressif sur le load factor, ce qui dans certains cas particulier peut être intéressant
C'est une solution auto-contenu. On corrige les structures de données qui pose problème. Ca veut dire que n'importe qui peut faire de même avec ses structures de données. Souvent la solution est de la tambouille interne au JDK. C'est dégueulasse par ce que le message c'est: "On a fait un truc pour nous mais toi développeur t'es dans la merde alors que tu as le même problème" et c'est bien trop courant.
Complexifier la classe pour moi est un faux problème. Ce n'est pas très complexe, le design s'explique facilement et c'était déjà complexe. Ça se test très facilement (et de manière exhaustive). Ça pourrait prendre un an à développer, ça reste une classe utilisée par le monde entier donc seul le résultat final compte c'est d'ailleurs pour ça qu'on te fourni ces classes.
J'aurai préféré qu'ils enrichissent l'API de HashMap avec un constructeur qui permette de passer une fonction de hashage, comme TreeMap avec le Comparator. De cette manière, le développeur choisi si il veut se protéger de l'attaque ou pas.
Ça pourrait être quelque chose d'orthogonal au fait d'améliorer le pire cas. En pratique je ne suis pas certain de l'utilité de la chose pour les raisons suivantes:
Si la complexité au pire cas est raisonnable, c'est beaucoup moins critique
Il faut faire super attention à ce que le contrat entre equals et hashCode soit respecté.
Pour les hashCode "lent" tu veux en général les cacher une fois qu'ils ont été calculés. C'est notamment le cas avec String. Avec un hachage externe à l'objet ça devient compliqué, crado ou dangereux.
[^] # Re: Questions
Posté par ckyl . En réponse au journal OpenJDK JEP 180: HashMap, collisions & attaques par la complexité. Évalué à 10.
Je fais rarement des choses dénonciatrices ;) C'est beaucoup plus intéressant de comprendre le processus et l'idée qu'il y a derrière un changement. En l’occurrence, l'auteur de ce changement à pas mal expliqué les choses sur reddit.
Après on peut émettre un avis: le sien. Pour ce changement je comprends parfaitement le rationnel, et je pense que par défaut le comportement actuel est le bon. Il y a plus de monde qui se faisait piéger par la référence gardée sur le buffer original que de gens écrivant des parser sachant ce qu'ils font (et plus de gens intéressés à gagner 8 octets par instance). À l'époque j'avais même du écrire un agent pour essayer d'identifier les substring qui survivaient à plusieurs GC pour auditer une grosse base de code. Ce qui est beaucoup plus discutable c'est que maintenant il soit impossible d'avoir accès à l'ancien comportement et de l'avoir fait dans une mineure.
Mais la leçon la plus intéressante, c'est de voir que ce deuxième changement a été précipité par l'ajout de
hash32qui était une mauvaise réponse au problème.Je ne suis pas d'accord avec ça. La réponse de la JEP 180 est pour moi la bonne: corriger la structure de donnée pour offrir une meilleure complexité au pire cas et une performance équivalente au cas moyen.
Complexifier la classe pour moi est un faux problème. Ce n'est pas très complexe, le design s'explique facilement et c'était déjà complexe. Ça se test très facilement (et de manière exhaustive). Ça pourrait prendre un an à développer, ça reste une classe utilisée par le monde entier donc seul le résultat final compte c'est d'ailleurs pour ça qu'on te fourni ces classes.
Ça pourrait être quelque chose d'orthogonal au fait d'améliorer le pire cas. En pratique je ne suis pas certain de l'utilité de la chose pour les raisons suivantes:
Mais ça demande d'y réfléchir plus longuement.