Vous êtes nouveau sur Developpez.com ? Créez votre compte ou connectez-vous afin de pouvoir participer !

Vous devez avoir un compte Developpez.com et être connecté pour pouvoir participer aux discussions.

Vous n'avez pas encore de compte Developpez.com ? Créez-en un en quelques instants, c'est entièrement gratuit !

Si vous disposez déjà d'un compte et qu'il est bien activé, connectez-vous à l'aide du formulaire ci-dessous.

Identifiez-vous
Identifiant
Mot de passe
Mot de passe oublié ?
Créer un compte

L'inscription est gratuite et ne vous prendra que quelques instants !

Je m'inscris !

Java : une piste intéressante pour améliorer les types génériques
Un prototype de « generic specialization » en cours de développement

Le , par Amine Horseman

239PARTAGES

1  0 
Même si Java 9 n’est pas encore prêt, une équipe de développeurs est chargée de préparer les nouvelles fonctionnalités de la version 10. Annoncé en juillet dernier, le projet Valhalla, dirigé par Brian Goetz, a pour but d’étudier et tester ces nouvelles fonctionnalités dont la publication est prévue pour 2016.

Il y a quelques jours, Goetz publia un document où il présente l’état d’avancement concernant la gestion des types génériques, l’une des caractéristiques les plus critiquées du Java puisqu’il n’est pas possible, actuellement, d’appliquer des génériques aux types primitifs.

Étant donné qu’Oracle accorde une importance primordiale à la compatibilité avec les versions précédentes, le problème soulevé de par l’introduction d’un tel système de « génériques améliorés » doit être approché avec prudence. En effet, la difficulté est que le « système de types du langage Java n'a pas de racine unifiée », il n'y a pas de type en Java qui est à la fois un super-type d’« Object » et de « int ».

Comme l’explique Goetz, « l'un des premiers compromis avec les génériques en Java est que ces variables ne peuvent être instanciées qu’avec les types de référence, et non pas les types primitifs […] Nous voulons permettre aux classes génériques existantes d’être améliorées, sans avoir à les jeter et les remplacer par de nouvelles. Et en même temps ne pas forcer les programmes existants à être recompilés ou modifiés simplement pour continuer à travailler ».

Pour cela, plusieurs techniques potentielles sont en train d’être étudiées. L’une des pistes les plus prometteuses, appelée « generic specialization », consiste à continuer à représenter les types du genre List<Integer> et List<String> par List.class dans le runtime, tandis que les nouvelles déclarations du genre List<int> seront représentées par un autre type.

L’équipe du projet Valhalla est en train de préparer un prototype pour tester cette technique. Cependant, il est encore tôt pour savoir si elle permet de résoudre efficacement tous les problèmes actuels du typage générique de Java.

Source : Open JDK

Une erreur dans cette actualité ? Signalez-le nous !

Avatar de adiGuba
Expert éminent sénior https://www.developpez.com
Le 31/12/2014 à 12:29
Citation Envoyé par thelvin Voir le message
Hmmm. Bon ça a l'air de marcher. Ça va encore démultiplier les classes à charger en mémoire mais ça on n'y aurait pas coupé à un moment ou à un autre.
C'est atténué par le fait que cela ne concernera que les primitifs/valeurs.
Les Generics avec des références fonctionneront toujours de la même manière.

Citation Envoyé par thelvin Voir le message
Ça va tout de même commencer à devenir compliqué, la lecture des JavaDoc des classes standard Java : "alors les méthodes remove(Object) et remove(int) elles existent que sur les instances où le E de List<E> est un type référence. Pour les types primitifs ça existe pas, utilisez removeItem(E) et removeIndex(int)"
Dans l'idée removeItem(E) et removeIndex(int) seront disponible pour tous les types, et les remove(Object)/remove(int) accessible uniquement pour les références pour la rétrocompatibilité.

Depuis Java 8 la javadoc inclut des onglets pour regrouper les méthodes selon plusieurs critères (instance, static, abstraite, concrète, default...).
On aura peut-être de nouveaux onglets pour gérer cela...

Mieux : c'est absent de ce document, mais dans la version précédente ils parlaient carrément de pouvoir faire une implémentation spécifique pour certains types.
Il serait ainsi possible par exemple d'avoir une implémentation d'ArrayList<boolean> basé sur un BitSet au lieu d'un boolean[]

Citation Envoyé par super_navide Voir le message
Je comprend pas bien ce genre d'évolution qui n'apporte pas grand chose.
C'est un prérequis à l'intégration des types valeurs.
Il serait absurde d’insérer des types valeurs dans le langage si on ne peut pas les utiliser avec les Generics.

Citation Envoyé par super_navide Voir le message
Il ferait mieux de faire en sorte de faire évoluer java pour avoir des performance équivalente a du C++.
Troll ? Ou alors tu es resté bloqué sur la fin des années 90 ?
Un peu de sérieux voyons...

Citation Envoyé par super_navide Voir le message
La nouvelle fonctionnalité values prévu je sais pas dans quelle version était très intérréssante.
Ben c'est le même projet : tout ceci est lié.
Sans specialization l'utilisation des types valeurs risque d'être problématique...

Citation Envoyé par super_navide Voir le message
Sinon une fonctionnalité a embarquer dans JDK serait de pouvoir produire un executable qui ne néssécité pas d'avoir un JRE d'installer sur le PC.
Cela existe déjà (mais pas dans le JDK en effet).
Par contre je n'y vois pas grand intérêt...

Citation Envoyé par super_navide Voir le message
Je pense java souffre d'un seul problème ne pas être totalement géré comme python ou C++ pas communauté indépendante.
Je ne comprend pas trop.
Même si c'est chapeauté par Oracle l'évolution de Java est entre les mains de plusieurs entreprises/organisations...

Citation Envoyé par redcurve Voir le message
C'est vraiment n'importe quoi cette techno
Soit tu argumentes, soit c'est du troll pure et le mieux serait d'aller voir ailleurs.
Ici on préfère les discussions argumentés aux petites phrases toutes faites qui ne veulent rien dire...

Citation Envoyé par gstratege Voir le message
Ça sert à quoi d'avoir des types primitifs ?
Les types primitifs sont des types de base sans notion d'identité. Ils ne représente qu'un espace mémoire réservé à la valeur qu'ils représente.
Les types valeurs sont des types primitifs un peu plus évolué, dans le sens où ils peuvent être composé de plusieurs éléments (un peu comme une structure en C).

Leurs utilités en Java est restreinte, car en les utilisant on "perd" plein de fonctionnalité (pas d'héritage).

Toutefois cela a deux gros intérêts :
  • Une occupation mémoire fixe, qui permet des allocations en bloc pour les tableaux.
    Un tableau de 10 int occupera toujours la même taille en mémoire quelque soit les valeurs stockées, tandis qu'un tableau de 10 Object occupera plus ou moins de mémoire selon les objets qu'on y met.
  • Elle ne comporte que des données, et aucune informations d'identité propre à l'héritage et la POO.
    Cela permet d'être "partagé" plus facilement avec du code natif, ou des instructions bas-niveau, sans avoir à faire des conversions dans tous les sens.


C'est important lorsqu'on fait des traitements 3D ou d'autres choses qui peuvent être manipulé directement par le GPU : on génère les données en Java et on les passe tel-quel pour un traitements optimisés (voir même parallélisés).

Citation Envoyé par tomlev Voir le message
En tous cas c'est une très bonne chose qu'ils se penchent enfin sur l'amélioration des génériques; c'est vraiment la feature la plus bancale de Java... Le design actuel partait d'un bon sentiment (garder la compatibilité avec le code déjà compilé existant), mais ça introduit tellement de limitations qu'à mon avis les inconvénients surpassent largement les bénéfices.
Ils ne vont pas tout changer : les Generics fonctionneront quasiment de la même manière pour les objets.
Ils vont juste introduire une système de template (un peu à la C#), mais uniquement pour les primitives/valeurs.

Sinon perso je ne trouve pas que l'implémentation des Generics soit aussi mauvaise que tout le monde le laisse entendre.
Au contraire je trouve que ses inconvénients sont largement plus décriés qu'ils ne le devraient, et qu'ils y a d'autres avantages qui sont mis sous silence :
  • La compatibilité avec le code déjà compilé comme tu le dis,
  • Mais également l’inter-compatibilité entre du code n'utilisant pas les Generics, et du code les utilisant, au sein d'un même programme sans avoir à faire des conversions.
  • Une covariance/contravariance plus complète, et pas limité à la déclaration du type, et cela dès le début.
  • Une compatibilité avec tous les langages tournant sur une JVM, même si ceux-ci n'ont pas forcément de notion de Generics.


a++
4  0 
Avatar de adiGuba
Expert éminent sénior https://www.developpez.com
Le 13/01/2015 à 17:39
Citation Envoyé par Logan Mauzaize Voir le message
Ayant la flemme de lire, les types primitifs ne sont pas compatibles avec la valeur null. Je suppose que rien n'a changé dans la proposition ?
La problématique des cas comme Map est-elle traité ? Bien que dans Java 8, ils aient ajouté les notions "IfAbsent"/"IfPresent" et "DefaultValue" dans les collections ...
Les types primitifs resteront tel quel (et donc n'accepterons pas null).
Quand aux cas comme Map, la specialization des Generics permettra de définir du code et des méthodes spécifiques pour des types.
Ainsi get(K) sera réservé aux objets, et on sera obligé de passer par getOrDefault(K,V) pour les types primitifs/values...

Citation Envoyé par Logan Mauzaize Voir le message
Par contre, j'ai une proposition toute conne pour les types primitifs. Pourquoi ne pas supprimer les "Wrappers" et utiliser des "paliatifs" simples pour le stockage en mémoire : tant que le type est sûr (sur la pile notamment, on ne stocke que la valeur binaire) et là où le type n'est pas sûr on stocke le valeur binaire plus un code sur 8-bits indiquant le type.
Le premier point est déjà fait par la JVM, qui peut optimiser pas mal de chose vira l'inlining et l'escape analysis...

Après changer la manière de stocker les primitifs n'apportera pas grand chose : ce ne sera pas aussi performants que de vrai primitif, et cela restera incompatible avec le code natif.
En Java il n'y a pas vraiment de gros soucis à passer par les types Wrapper.
Le problème c'est qu'on ne peut pas les passer tel quel vers le natif (logiciel ou matériel).

Et justement l'objectif des types valeurs est de définir des types values est de permettre de définir des structures de données identiques à ceux qu'on retrouve en natif, pour faciliter le partage des données.

Citation Envoyé par Logan Mauzaize Voir le message
Concernant le type-system de Java, je le trouve pas si compliqué. Mais je préfère largement celui de Ceylon conçu par .... le même fameux Gavin King qui proposait une autre façon d'aborder le problème. En ayant déporté la variance au niveau de la déclaration du type ("declaration-site variance" vs "use-site variance", Wikipedia, Gavin King), on sépare dans les interfaces la partie "production" (retour) et "consommation" (paramètre). Les APIs et l'utilisation sont beaucoup plus simple et lisible.
Oui une "declaration-site variance" est plus simple et lisible, même si elle a ses propres défauts (déclaration sur le type uniquement, découpage en plusieurs sous-interfaces, moins de cohérence de l'ensemble...).
En même temps il faut dire que les wildcards de Java sont vite très difficile à lire !

Au passage voir l'URL de la JEP que j'ai évoqué plus haut dans cette discussion (si je ne me trompe pas), et qui consiste à apporter la "declaration-site variance" dans Java : http://openjdk.java.net/jeps/8043488

Citation Envoyé par Logan Mauzaize Voir le message
Comme adiGuba, les génériques ne sont vraiment pas le truc le plus chiant comparé aux CheckedException et l'absence de type non signé, surtout "byte". D'autant que dans le premier cas, il n'y aurait rien d'alarmant à les rendre désactivable puisque le bytecode n'y ait pas sensible.
Les types values devraient permettre de créer des types non-signé (entre autres).

a++
1  0 
Avatar de adiGuba
Expert éminent sénior https://www.developpez.com
Le 14/01/2015 à 14:49
Citation Envoyé par Logan Mauzaize  Voir le message
C'est quoi la syntaxe retenue pour indiquer qu'une méthode est spécifique au référence ? Est-ce que l'on peut également faire l'inverse, avoir des méthodes spécifiques pour les valeurs ?

La syntaxe n'est pas du tout définitive. Pour le moment elle n'est donné que pour pouvoir "tester", mais il y a de forte chance que cela change.
Dans la dernière proposition il faut utiliser des layer pour définir des bloc de codes disponible pour l'un ou l'autre :
Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
interface Exemple { 
 
    public T methodeCommune(); 
 
    layer { 
         
        public T methodPourLesObjects(); 
 
    } 
}
On peut bien sûr définir des méthodes/attributs uniquement pour les valeurs avec layer (ce qui regroupe primitifs et type values).
Il devrait même être possible de définir cela pour un type précis (layer) voir même selon selon des critères d'héritage (layer>).

Citation Envoyé par Logan Mauzaize  Voir le message
Concrètement au niveau des classes ? On aura la construction dynamique d'une nouvelle classe pour les valeurs ? (Ex: List<int>.class != List<Object>.class).
Si oui, il y aura une classe par type valeur ou seulement une pour les références et une autre pour les valeurs ?
Et qui des types génériques qui accepteront plusieurs type paramétré "any" (ex: Map<any K, any V>)

Oui : on conservera une classe commune pour les références (comme actuellement), mais il y aura une classe pour chaque configuration utilisant une primitif/valeur.
Toutefois comme en C# cela devrait être fait dynamiquement à l'exécution (ie : lorsque tu compiles ta classe tu as un fichier .class, et la JVM génèrera automatiquement les différentes classes à l'utilisation).
Et on pourra bien sûr avoir plusieurs types génériques "anyifié" (ex: Map<any K, any V>)

Citation Envoyé par Logan Mauzaize  Voir le message
Ce que je propose c'est de supprimer le boxing. C'est en tout cas la problématique mise en avant par le papier :

Oui mais grosso-modo ta solution consiste à donner une identité aux primitives, en y ajoutant un header le décrivant.

Or si on veut partager les données avec du code natif, on ne peut pas utiliser cela car on doit utiliser exactement la même structure mémoire...

Citation Envoyé par Logan Mauzaize  Voir le message
Ce que je propose c'est justement de garder des primitifs et juste d'ajouter la surcouche nécessaire au type safe là ou c'est nécessaire (bien que je ne suis pas sûr que ce le soit). Beaucoup de langages passent par le tout objet, il serait intéressant de voir comment ils gèrent tout ca.
Pour moi, les types primitifs doivent être vu par le codeur comme un type référence et exploiter en interne de manière native avec des appels statiques dans le bytecode et inliner au JIT.

La JVM fait déjà pas mal de chose comme cela.
Le problème c'est pas vraiment les performances de la JVM en elle même, mais plus de la manière dont on communique avec "l'extérieur".
Passes une zone mémoire avec un tel header vers du code natif, et il ne pourra pas le lire "nativement".

Or l'objectif des types values c'est surtout ca : pourvoir représenter des données en mémoire de la même manière qu'en natif, afin de pouvoir communiquer plus facilement avec du natif (que ce soit logiciel ou hardware).

Citation Envoyé par Logan Mauzaize  Voir le message
Les wildcards sont difficiles à lire et à manipuler. On se demande toujours à quel cas correspond la covariance et la contravariance et avec quel mot clé on l'exprime (extends ou super). C'est pourquoi je préfère les mots clé de Ceylon : in / out. Et le découpage des interfaces d'un côté le consommateur et de l'autre le producteur.
On se retrouve parfois avec des incompatibilités de type alors que ce ne devrait pas être le cas.

Oui, c'est bien ce que je dis : les wildcards sont plus complexes, mais permettent aussi plus de chose.

Citation Envoyé par Logan Mauzaize  Voir le message
Le problème c'est qu'à moins de casser la rétrocompatibilité, il est déjà trop tard. Toutes les méthodes qui manipulent des byte sont signés. En espérant qu'ils ajoutent tout de même un unsigned byte en natif avec éventuellement un moyen de conversion "transparent" pour passer de l'un à l'autre. Ainsi on pourrait réutiliser les APIs existantes.
Bien que je vois pas comment optimiser le cas des tableaux ...

Non justement les types values devraient permettre cela. On pourra définir une infinité de type...
Après tout en mémoire il n'y a aucune différence entre un byte et un unsigned byte : il s'agit juste d'un octet.
La seule différence vient de l'implémentation des calculs et des opérations que l'on effectue dessus (d'ailleurs Java 8 a rajouté des méthodes dans les classe Integer/Long afin de traiter les int/long en tant qu'unsigned.)

Il serait donc possible de définir un type value contenant un byte, que l'on manipulerait comme un unsigned.

a++
1  0 
Avatar de thelvin
Modérateur https://www.developpez.com
Le 30/12/2014 à 1:52
Hmmm. Bon ça a l'air de marcher. Ça va encore démultiplier les classes à charger en mémoire mais ça on n'y aurait pas coupé à un moment ou à un autre.

Ça va tout de même commencer à devenir compliqué, la lecture des JavaDoc des classes standard Java : "alors les méthodes remove(Object) et remove(int) elles existent que sur les instances où le E de List<E> est un type référence. Pour les types primitifs ça existe pas, utilisez removeItem(E) et removeIndex(int)"
Si ce truc passe je tire mon chapeau à ceux qui arrivent encore à décrocher des certifs Java.
0  0 
Avatar de ternel
Expert éminent sénior https://www.developpez.com
Le 31/12/2014 à 9:48
Justement, pouvoir avoir des list<int> qui ne passent pas par une conversion vers Integer pourra fortement augmenter les performances de tout programme de calcul.

Quant à "je pense que c'est le meilleur langage parce qu'on peut tout faire", c'est aussi vrai pour tout un tas d'autres langages, comme le C++, le C#, le python, etc.
Le bon outil est celui adapté à la tache.

Personne ne dira "le marteau est le meilleur outil", pourtant, on peut tout faire avec... planter des vis (c'est pas idéal, mais ca marche), cirer des chaussures, démarrer un tracteur, et même coudre un bouton.
0  0 
Avatar de redcurve
Membre éclairé https://www.developpez.com
Le 31/12/2014 à 9:49
Citation Envoyé par super_navide Voir le message
Je comprend pas bien ce genre d'évolution qui n'apporte pas grand chose.

Il ferait mieux de faire en sorte de faire évoluer java pour avoir des performance équivalente a du C++.
La nouvelle fonctionnalité values prévu je sais pas dans quelle version était très intérréssante.
Sinon une fonctionnalité a embarquer dans JDK serait de pouvoir produire un executable qui ne néssécité pas d'avoir un JRE d'installer sur le PC.

Je pense java souffre d'un seul problème ne pas être totalement géré comme python ou C++ pas communauté indépendante.

Mais bon malgré. tous ses défaut je pense que c le meilleur langage car on peut tous faire avec java.

Mais c# arrive pas loin , avec le nouveau framework que microsoft fait qui permet d'écrire une application pour la plupard des plateformes est intéressant.
Mais c# souffre du même problème que java il est la propriété de microsoft.
C# n'est pas la propriété de MS c'est une spec, pareil pour la CLR et la CLI.

Le .net Framework n'est qu'une implémentation de la CLR/CLI sous Windows.

Toutes les specs sont dispo librement sur le site de l'ECMA
0  0 
Avatar de gstratege
Membre habitué https://www.developpez.com
Le 31/12/2014 à 10:01
Ça sert à quoi d'avoir des types primitifs ?
0  0 
Avatar de tomlev
Rédacteur/Modérateur https://www.developpez.com
Le 31/12/2014 à 10:35
Citation Envoyé par super_navide Voir le message
Mais c# souffre du même problème que java il est la propriété de microsoft.
C'est plus tout à fait vrai :
- d'une part, le langage est standardisé par l'ECMA (du moins jusqu'à la version 2 ; je ne sais pas s'ils ont l'intention de faire standardiser les versions suivantes)
- d'autre part, le compilateur est maintenant open-source et cross-platform, et la communauté est fortement impliquée dans sa conception

Certes, c'est toujours Microsoft qui pilote l'évolution du langage, mais je ne vois pas en quoi c'est pire que Java qui est maintenant piloté par Oracle...

Citation Envoyé par gstratege Voir le message
Ça sert à quoi d'avoir des types primitifs ?
Pour des questions de performance, principalement. Les types primitifs correspondent directement à des types de données supportés par le processeur (int, double, etc), qui peuvent donc être traités très efficacement.

En tous cas c'est une très bonne chose qu'ils se penchent enfin sur l'amélioration des génériques; c'est vraiment la feature la plus bancale de Java... Le design actuel partait d'un bon sentiment (garder la compatibilité avec le code déjà compilé existant), mais ça introduit tellement de limitations qu'à mon avis les inconvénients surpassent largement les bénéfices.
1  1 
Avatar de oallouch
Futur Membre du Club https://www.developpez.com
Le 31/12/2014 à 15:23
Brian Goetz et son équipe avancent vraiment bien côté langage.
Les lambdas de Java 8 sont une merveille (regardez le source de la classe utilitaire Collectors).
Ils ont pris le temps mais c'est du bon !
Avec ces maj dans Java 9, ils vont résoudre le truc le plus chiant avec les lambdas pour les Collections:
ils vont pouvoir ajouter une méthode stream() à l'interface Iterator...le bonheur !

Maintenant, il faudrait vraiment qu'ils se penchent (je crois qu'ils le font) sur la pauvreté du Hot Swap standard et la nécessité pour tous d'avoir en standard (et gratuit) un truc équivalent à JRebel. Il existe déjà des produits open source (moyennement supportés) comme DCEVM.

Mais, je peux vous dire que quand vous passez de Javascript (quand vous codez votre UI) à Java (pour le serveur), vous respirez !

Olivier Allouch
http://www.illicotravel.com
0  0 
Avatar de tomlev
Rédacteur/Modérateur https://www.developpez.com
Le 31/12/2014 à 18:31
Citation Envoyé par adiGuba  Voir le message
Ils vont juste introduire une système de template (un peu à la C#), mais uniquement pour les primitives/valeurs.

En C# c'est pas vraiment un système de template (dans le sens des templates C++). Le compilateur produit un seul type générique ouvert, et c'est au runtime que les types fermés sont créés (éventuellement dynamiquement par réflexion). Alors qu'en C++, toutes les instanciations d'un template sont générées directement à la compilation ; ça a certains avantages (performance, plus de souplesse puisqu'on peut faire n'importe quelle opération dans un template du moment que le type utilisé lors de l’instanciation le supporte), mais ça a l'inconvénient d'être complètement statique...

Citation Envoyé par adiGuba  Voir le message
[*] Une covariance/contravariance plus complète, et pas limité à la déclaration du type, et cela dès le début.

Oui mais la variance des génériques en Java n'est pas type-safe... Petit exemple de quelque chose qui va compiler sans problème mais échouer à l'exécution :
Code Java : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import java.util.List; 
import java.util.ArrayList; 
  
public class GenericTypeErasure { 
  public static void main(String[] args) { 
    List<Foo> fooList = new ArrayList<Foo>(); 
    List<?> list = fooList; 
    List<Bar> barList = (List<Bar>)list; 
    barList.add(new Bar()); // no error 
    Foo foo = fooList.get(0); // java.lang.ClassCastException: HelloWorld$Bar cannot be cast to HelloWorld$Foo 
  } 
  
  static class Foo { 
  } 
  
  static class Bar { 
  } 
}

En C#, ce serait impossible. Les classes génériques ne sont pas variantes ; seules les interfaces (et les delegates) peuvent l'être, mais il y a des contraintes. Par exemple, l'interface IList n'est pas covariante, parce que T apparait à la fois en sortie et en entrée (un IList ne peut donc pas être affecté à un IList). Par contre, IEnumerable est covariante, car T n'apparait qu'en sortie (un IEnumerable peut être affecté à un IEnumerable)

Après, je reconnais volontiers que l'approche de Java a certains avantages... Il m'arrive occasionnellement de regretter que les wildcards n'existent pas en C#, même s'ils présentent certains risques (comme l'exemple ci-dessus)
0  0