Voir le flux RSS

bouye

[Actualité] JEP 286 : inférence du type des variables locales

Note : 2 votes pour une moyenne de 5,00.
par , 14/03/2016 à 23h59 (2590 Affichages)
Un reproche qui revient régulièrement en ce qui concerne Java est le fait que le langage semble plutôt « verbeux » comparé à d'autres langages plus modernes. Par exemple, il convient d'écrire :

Code Java : Sélectionner tout - Visualiser dans une fenêtre à part
LinkedList<String> stringList = new LinkedList<String>()

Même si des améliorations dans le langage apportées lors des JDK 7 et 8 permettent désormais d'écrire LinkedList<String> stringList = new LinkedList<>(), voire LinkedList<String> stringList = new LinkedList() (au prix de quelques warnings suivant la configuration de votre IDE), il reste que la déclaration obligatoire du type à gauche est redondante dans bien des cas et peut sembler assez souvent inutile.

Une nouvelle proposition d'amélioration du JDK (JEP ou JDK Enhancement Proposal) en date du 8 mars 2016 vient de voir le jour, la JEP 286: Local-Variable Type Inference. Le but de cette nouvelle proposition est d'introduire le type réservé var ou val pour permettre donc de rendre les déclarations des variables locales plus concises et ainsi se rapprocher de ce qui se fait dans des langages concurrents (*atchoum* C# *atchoum* ; ainsi le typeréservé auto du C++ n'aura pas été retenu). La proposition mentionne également qu'il serait possible d'introduire val ou let en tant que raccourci syntaxique pour final var.

Si la proposition est retenue, ce mot serait utilisable pour les variables locales, les boucles for-each et les boucles for traditionnelles. Il ne serait pas utilisable pour les paramètres de méthode ou d'un constructeur, la valeur de retour d'une méthode, le catch ou encore la déclaration des membres d'une classe. Il deviendra alors possible d'écrire dans une variable locale d'une méthode : var list = new LinkedList<String>(); (le type est explicite puisque la variable est initialisée via l'appel d'un constructeur) ou encore var stream = list.stream(); (ici le type est inféré d'après le type de retour de la fonction).

De plus, certains aménagements dans les règles habituelles seront nécessaires : il y a trop de code existant pouvant utiliser var ou val comme nom de variable, et il est donc impossible de faire que ces mots soient définis en tant que mots-clés du langage d'où le choix d'un type réservé. Enfin, un travail de simplification doit être fait au niveau du compilateur pour rendre les messages d'erreurs plus facilement interprétables par le programmeur dans les cas suivants où l'inférence est impossible :


-> erreur : la variable n'est pas initialisée, impossible d'inférer son type.

Code Java : Sélectionner tout - Visualiser dans une fenêtre à part
var f = () -> { };

-> erreur : le type de la lambda doit être explicite.


-> erreur : initialisé à null, impossible d'inférer son type.


-> erreur : impossible de dénoter le type inféré (? il faudrait voir le type déclaré de l() dans le code de test).


-> erreur : le type de la référence de méthode doit être explicite.

Code Java : Sélectionner tout - Visualiser dans une fenêtre à part
var k = { 1 , 2 };

-> erreur : le type du tableau doit être explicite.

Envoyer le billet « JEP 286 : inférence du type des variables locales » dans le blog Viadeo Envoyer le billet « JEP 286 : inférence du type des variables locales » dans le blog Twitter Envoyer le billet « JEP 286 : inférence du type des variables locales » dans le blog Google Envoyer le billet « JEP 286 : inférence du type des variables locales » dans le blog Facebook Envoyer le billet « JEP 286 : inférence du type des variables locales » dans le blog Digg Envoyer le billet « JEP 286 : inférence du type des variables locales » dans le blog Delicious Envoyer le billet « JEP 286 : inférence du type des variables locales » dans le blog MySpace Envoyer le billet « JEP 286 : inférence du type des variables locales » dans le blog Yahoo

Mis à jour 17/03/2016 à 10h14 par ClaudeLELOUP

Catégories
Java , Java

Commentaires

Page 1 sur 2 12 DernièreDernière
  1. Avatar de Gugelhupf
    • |
    • permalink
    Oui enfin si on part du principe que var est un plagiat de C# alors que JS ES6 et Swift utilisent var / let, on se demande quelle est l'origine même de C#.
    Ce que je me pose comme question, c'est qu'ils ont évités de mettre en place ces mots-clés en mettant en place le diamond operator, et du coup ils feraient un pas en arrière ?
    Il y a peut-être une volonté de casser la compatibilité avec les modules + inférence de type ? Autant en profiter pour enlever le type erasure et mettre en place la reification.
  2. Avatar de adiGuba
    • |
    • permalink
    Salut,

    Citation Envoyé par Gugelhupf
    Autant en profiter pour enlever le type erasure et mettre en place la reification.
    Le type erasure n'apporterait pas grand chose sur des références... tout en cassant toute compatibilité !
    Par contre on pourrait éventuellement avoir quelques sucres syntaxiques pour les quelques limitations que cela implique (pour new T[] par exemple).



    Le principal intérêt de la reification concerne les primitifs et les type-valeurs, et tout cela est prévu dans le cadre du projet Valhalla...


    a++
  3. Avatar de bouye
    • |
    • permalink
    Citation Envoyé par Gugelhupf
    Oui enfin si on part du principe que var est un plagiat de C# alors que JS ES6 et Swift utilisent var / let, on se demande quelle est l'origine même de C#.
    Dans la mesure où C# est (plusieurs fois) explicitement mentionné dans la proposition, il devient clair que leur cible / inspiration n'est pas un autre langage ; après C# a pu copier ce qu'il veut (JavaScript ou des languages fonctionnels préexistants), là n'est pas le problème.

    Nearly all other popular statically typed "curly-brace" languages, both on the JVM and off, already support some form of local-variable type inference: C++ (auto), C# (var), Scala (var/val), Go (declaration with :=).

    [...]

    var x = expr only (like C#)

    [...]

    Auto is a viable choice, but Java developers are more likely to have experience with Javascript, C#, or Scala than they are with C++, so we do not gain much by emulating C++ here.
    D'autant plus que ce n'est pas juste la syntaxe qui est visée ici mais le mode de fonctionnement de l’inférence de type.

    Et sinon C# est lui-même un plagiat de J# (toujours de Microsoft) et donc de Java de toute manière, et donc, encore une fois, (comme beaucoup de cross-copiage C# <-> Java) les deux frères siamois continuent d’évoluer en parallèle.
  4. Avatar de grunk
    • |
    • permalink
    Dommage pour auto, je trouve ça plus parlant que var
  5. Avatar de Washmid
    • |
    • permalink
    C'est la situation qui me gène le plus (je fais pas mal de c# au boulot). Écrire ça revient à masquer une dépendance envers le type retour de l()... C'est même masqué dans les imports / using en début de fichier !

    Ceci dit on a le même problème avec les lambdas...

    Là par contre un sucre syntaxique pourquoi pas (cf. adiGuba) mais franchement on peut vivre sans.
  6. Avatar de micka132
    • |
    • permalink
    Citation Envoyé par Gugelhupf
    Oui enfin si on part du principe que var est un plagiat de C# alors que JS ES6 et Swift utilisent var / let, on se demande quelle est l'origine même de C#.
    Tu parles de swift d'apple sorti en 2014? Le var de c# date de 2007.Concernant celui de JS il n'a pas la même signification.En C# on est sur du fortement typé, le compilateur va donc t'envoyer promener si après la déclaration tu essayes une affectation d'un autre type, et il va également te permettre d'avoir de l'autocomplétion (l'equivalent du var JS en c# est le mot clé dynamic).
    Le var à pas mal son utilité pour des types anonymes ainsi que pour le retour de requête Linq/lambda avec des types à rallonge dont franchement on se fout. D'ailleurs le mots clé var est sortie en même temps que Linq (2007) c'est surement lié.
  7. Avatar de Gugelhupf
    • |
    • permalink
    JS ES6 et Swift c'était pour l'exemple car ils sont à la mode en ce moment, ce couple de mot-clé est présent depuis très très lontemps dans certains langages (ex: OCaml). Encore une fois je ne considère pas cela comme du plagiat, mais c'est la proposition en lui-même qui me choque car ils ont mis en place le diamond operator pour justement éviter l'inférence de type il me semble, pourquoi revenir en arrière ? Le diamond operator et inférence de type ne sont pas compatible par exemple, il aurait surement été préférable de rester sur une décision.

    adiGuba, je serais le premier à défendre les features de Java, et je suis d'accord sur le fait que le type erasure permet de faire beaucoup de choses... sauf que la reification rend le développement plus naturel (sans passer un Toto.class en paramètre de méthode) et permet d'aller plus loin pour récupérer des types au runtime (ParameterizedType), ce que ne permet pas le type erasure. Avoir la reification permettrait aussi d'avoir des API plus user-friendly (ps: regarde le client de mongo Java vs C#, c'est le jour et la nuit).
  8. Avatar de adiGuba
    • |
    • permalink
    Citation Envoyé par Gugelhupf
    JS ES6 et Swift c'était pour l'exemple car ils sont à la mode en ce moment, ce couple de mot-clé est présent depuis très très lontemps dans certains langages (ex: OCaml). Encore une fois je ne considère pas cela comme du plagiat, mais c'est la proposition en lui-même qui me choque car ils ont mis en place le diamond operator pour justement éviter l'inférence de type il me semble, pourquoi revenir en arrière ? Le diamond operator et inférence de type ne sont pas compatible par exemple, il aurait surement été préférable de rester sur une décision.
    Le diamond operator c'est déjà de l'inference de type... mais dans l'autre sens.

    Code java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    // Ecriture complète :
    List<String> list = new ArrayList<String>();
     
    // Inférence de type avec le diamond operator :
    // le type du paramétrage Generics est déterminé selon le contexte, ici la déclaration de la variable "list" :
    List<String> list = new ArrayList<>();
     
    // Inférence de type avec "var/val/let" :
    // le type de la variable "list" est déterminé selon le contexte, ici l'allocation de l'objet :
    var list = new ArrayList<String>();


    Si on ne peut pas utiliser les deux en même temps, c'est parce qu'on n'a plus aucune info du tout pour l'inference :
    Code java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    var list = new ArrayList<>(); // ERREUR : on ne connait pas le paramétrage
    // comment le compilateur pourrait-il déterminer qu'on souhaite manipuler des String et pas des Dates ou autre ???



    Citation Envoyé par Gugelhupf
    adiGuba, je serais le premier à défendre les features de Java, et je suis d'accord sur le fait que le type erasure permet de faire beaucoup de choses... sauf que la reification rend le développement plus naturel (sans passer un Toto.class en paramètre de méthode) et permet d'aller plus loin pour récupérer des types au runtime (ParameterizedType), ce que ne permet pas le type erasure. Avoir la reification permettrait aussi d'avoir des API plus user-friendly (ps: regarde le client de mongo Java vs C#, c'est le jour et la nuit).
    Le problème c'est que beaucoup de gens considère l'erasure comme une erreur de Java. Il n'en est rien.
    C'est un compromis avec ses avantages et ses défauts... tout comme la réification !

    Le "Toto.class" en paramètre pourrait être géré via du sucre syntaxique si tu utilises T.class dans ta classe Generics, par exemple.
    Pas besoin de reification pour cela.


    La reification entraine plein de contrainte également :
    • L'absence de "raw-type", et donc une incompatibilité avec beaucoup de code existant.
    • L'impossibilité de "Genericifier" une classe existante sans provoquer de grosses incompatibilités.
    • Des limitations aux niveaux des wildcards.
    • Il y a un surcoût de complexité et d'utilisation car il faut créer dupliquer des types (List<String>.class != List<Date>.class), sans que cela n'apporte aucun intérêt avec les références (le code reste le même).
    • Ce n'est pas compatible avec des langages faiblement typés ( que faire de new List() ???? ) ou des langages ayant leurs propres Generics (Scala par exemple).



    La direction prise par le projet Valhalla me semble bien adapté : conserver l'erasure pour les références, et une "reification" uniquement pour les types-valeurs (car là cela à un gros intérêt).


    a++
  9. Avatar de Gugelhupf
    • |
    • permalink
    Citation Envoyé par adiGuba
    La reification entraine plein de contrainte également :
    • L'absence de "raw-type", et donc une incompatibilité avec beaucoup de code existant.
    • L'impossibilité de "Genericifier" une classe existante sans provoquer de grosses incompatibilités.
    • Des limitations aux niveaux des wildcards.
    • Il y a un surcoût de complexité et d'utilisation car il faut créer dupliquer des types (List<String>.class != List<Date>.class), sans que cela n'apporte aucun intérêt avec les références (le code reste le même).
    • Ce n'est pas compatible avec des langages faiblement typés ( que faire de new List() ???? ) ou des langages ayant leurs propres Generics (Scala par exemple).



    La direction prise par le projet Valhalla me semble bien adapté : conserver l'erasure pour les références, et une "reification" uniquement pour les types-valeurs (car là cela à un gros intérêt).
    Je ne vois pas d'incompatibilité ou de complexité avec la reification (l'inverse oui par contre), de souvenir j'avais lu quelque part que le gars qui l'a mis en place en C# et Java (une même personne) avait dit que l'implémentation était plus simple en C# :
    • Les raw-type existent en C#
    • Wildcard : List<?> <=> List<? extends Object> <=> List<Object>
    • "uniquement pour les types-valeurs" : des spécificités en plus à savoir, c'est dommage.
  10. Avatar de adiGuba
    • |
    • permalink
    Citation Envoyé par Gugelhupf
    Je ne vois pas d'incompatibilité ou de complexité avec la reification (l'inverse oui par contre),
    Des incompatibilités avec les Generics de Java ? Je demande à voir !

    En C# tu ne peux pas migrer une classe "normale" en Generics. Enfin pas sans casser toute compatibilité car les anciens codes ne s'exécuteront plus et ne compileront plus !
    En Java tu peux très bien faire cela sans tout casser. L'API de Collections de Java a pu évoluer en restant compatible alors qu'il y a deux API de Collections en C# (System.Collections vs. System.Collections.Generic).
    Si tu as des codes qui manipules l'ancienne et la nouvelle API, tu vas devoir faire des conversions de tous les cotés...


    Cela veut aussi dire qu'il n'y a aucun moyen de transformer une classe "normale" en classe Generics sans casser le code existant.


    Et surtout les types Generics ne peuvent pas être utilisé dans les langages faiblement typés... car il faut obligatoirement spécifié le type paramétré !
    Imagines un pseudo-code qui crée une liste non-typé :
    Sous une JVM on utilisera simplement new ArrayList() (sans paramétrage), et on pourra utiliser l'instance avec d'autre code de provenance diverse sans soucis.
    Sous .NET il n'y a pas de solution efficace pour utiliser l'API Generic... du coup cela pose des incompatibilités avec d'autres codes qui pourraient les utiliser...




    Citation Envoyé par Gugelhupf
    Les raw-type existent en C#
    Il existe peut-être un type qui représente la classe sans paramétrage, mais tu ne peux pas l'instancier sans paramétrage (d'où le problème précédent).
    Ou alors je ne connais pas la syntaxe !

    Citation Envoyé par Gugelhupf
    Wildcard : List<?> <=> List<? extends Object> <=> List<Object>
    ?
    Sauf erreur il n'y a pas de wildward en C#...
    A moins que cela ne concerne les dernières versions...


    Citation Envoyé par Gugelhupf
    "uniquement pour les types-valeurs" : des spécificités en plus à savoir, c'est dommage.
    Même en C# le code est partagé pour les références... car de toute manière c'est strictement le même !!!





    Le type-erasure revient souvent comme la "grosse" erreur de Java, mais perso je pense plutôt tout le contraire.
    Si je le pouvais, il y a bien d'autre chose que je changerais (l'héritage des tableaux, les checked-exceptions, l'overload des méthodes...), mais pas les Generics (sauf pour le support des type-valeurs bien sûr)


    a++
  11. Avatar de Gugelhupf
    • |
    • permalink
    Excuse-moi, petite confusion de ma part avec le terme "raw-type", je pensais au fait de pouvoir utiliser List<int> list = ... (qui sera possible en Java avec les value type un jour peut-être), et pas List list = .... Pour être franc avec toi adiGuba, utiliser les raw-type c'est très moche, et donc je ne défendrais pas cette cause de rétrocompatibilité, même si une migration devrait être effectué pour les codes pré-Java 1.4 ça vaut le coup (on met tout en <?> ou <Object> ). La rétrocompatibilité, bien que très puissante en Java, n'est de toute façon jamais assuré à 100%, toi tu vois le visible (code), mais tu as des cas où le problème touche le manifest et tu peux passer des heures à lire la doc pour comprendre qu'un cas n'est plus gérer de la même manière entre un Java 6 et Java 7 (cf: vécu avec les permissions pour faire du JNLP).

    Je n'ai jamais dit qu'il y avait des wildcard en C#, c'est juste qu'en Java : List<?> <=> List<? extends Object>, donc même avec un script on pourrait assurer la migration sans problème je pense.

    Je ne toucherais pas aux checked-exceptions, pour moi un bon code doit être un code prévisible. Si pendant le dév on oublie de gérer des exceptions et qu'un jour on rencontre un cas qu'on aurait pu gérer grâce aux checked-exception...
    Que ferais-tu pour l'overload ? Explicite comme en C++ et C# ?
  12. Avatar de adiGuba
    • |
    • permalink
    Citation Envoyé par Gugelhupf
    Excuse-moi, petite confusion de ma part avec le terme "raw-type", je pensais au fait de pouvoir utiliser List<int> list = ... (qui sera possible en Java avec les value type un jour peut-être), et pas List list = ....
    Oui c'est l'avantage de la reification : cela permet un code spécialisé pour les primitifs/type-valeurs.
    Mais pour cela il faut d'abord avoir des types-valeurs.

    Le projet Valhalla semble très intéressant... reste à savoir quand il prendra forme.


    Citation Envoyé par Gugelhupf
    Pour être franc avec toi adiGuba, utiliser les raw-type c'est très moche, et donc je ne défendrais pas cette cause de rétrocompatibilité, même si une migration devrait être effectué pour les codes pré-Java 1.4 ça vaut le coup (on met tout en <?> ou <Object> ).
    Le raw-type c'est moche... en Java !
    Mais je parlais de compatibilité et cela ne se limite pas à Java pre-1.4, mais également avec tous les langages qui peuvent tourner sur la JVM.

    Et <?> ou <Object> cela ne signifie pas la même chose :
    • List correspond à une liste non paramétré.
    • List<?> correspond à une liste paramétré, dont on ignore le type exact (ce qui limite l'appel à certaines méthodes).
    • List<Object> correspond à une liste paramétré avec Object.

    Les deux premiers n'existe pas en C# !


    Un langage faiblement typé peut utiliser les types Generics de Java via le raw-type sans soucis.
    Bien sûr le typeage n'est pas vérifié... mais quoi de plus normal dans un langage faiblement typé !

    Avec des Generics reified c'est plus compliqué car on n'a pas de telle solution : il faudra à tout prix typé l'instance même si le langage est faiblement typé.
    On pourrait utiliser le type <Object>, mais cela va engendrer des erreur de types...



    Citation Envoyé par Gugelhupf
    La rétrocompatibilité, bien que très puissante en Java, n'est de toute façon jamais assuré à 100%, toi tu vois le visible (code), mais tu as des cas où le problème touche le manifest et tu peux passer des heures à lire la doc pour comprendre qu'un cas n'est plus gérer de la même manière entre un Java 6 et Java 7 (cf: vécu avec les permissions pour faire du JNLP).
    Oui mais là on est en dehors du langage...


    Citation Envoyé par Gugelhupf
    Je n'ai jamais dit qu'il y avait des wildcard en C#, c'est juste qu'en Java : List<?> <=> List<? extends Object>, donc même avec un script on pourrait assurer la migration sans problème je pense.
    Non tu ne peux pas. List<?> n'est possible qu'avec le type-erasure. C'est trop complexe à gérer avec la reification (d'ailleurs cela n'existe pas en C#).
    Si Microsoft a dupliqué l'API de Collections ce n'est pas pour rien

    Fait un simple test : transforme une classe "normale" en classe Generics.
    Si tu conserves la même signature de méthode, en Java tout restera compatible :
    • Les sources continueront de compiler (en générant des warning).
    • Les binaires compilé avec l'ancienne classe continueront à s'exécuter normalement, même avec la nouvelle version de la classe.


    En C# c'est tout autre chose :
    • Les sources génèreront des erreurs qu'il faudra corriger pour compiler.
    • Les binaires compilé avec l'ancienne classe génèreront des erreurs si tu les exécutes avec la nouvelle version (équivalent du ClassNotFound).



    Citation Envoyé par Gugelhupf
    Je ne toucherais pas aux checked-exceptions, pour moi un bon code doit être un code prévisible. Si pendant le dév on oublie de gérer des exceptions et qu'un jour on rencontre un cas qu'on aurait pu gérer grâce aux checked-exception...
    Le problème c'est que c'est tellement lourd que ca fait plus chier qu'autre chose, et du coup on se retrouve à devoir traiter des exceptions là où l'on ne devrait pas avoir à le faire.
    Bien souvent il est préférable de faire planter le thread plutôt que de traiter une exception sans solution...

    Et je ne parle même pas des problèmes que cela pose avec les lambdas !!!
    Bref je trouve que c'était vraiment une mauvaise idée (d'ailleurs celle-là C# ne l'a pas repris !)


    Citation Envoyé par Gugelhupf
    Que ferais-tu pour l'overload ? Explicite comme en C++ et C# ?
    Perso j'interdirais l'overload (mais bon ca ne se fera pas ca devient un changement incompatible).

    Cela complique beaucoup de chose en apportant plein d’ambiguïté et des problèmes de résolution de méthode... pour pas grand chose en fait.

    Dans la majeur partie des cas on peut utiliser un nom différent ce qui règle le problème.
    Il y a juste deux cas où cela a vraiment un intérêt :
    • Pour gérer les types primitifs et les types valeurs (ex : les différentes versions de print()/println()).
      Mais cela pourrait être remplacé par une méthode Generics avec reification/spécialisation.
      Concrètement cela reste similaire, sauf que c'est fait après la résolution de la méthode.
    • Pour gérer des paramètres optionnels...
      Or sans overload des méthodes ce serait plus simple à faire de manière intégré au langage, car on pourrait sortir les paramètres de la signature.
      On pourrait donc avoir de vrai paramètres optionnels, et non pas un "hack" bien verbeux...




    a++
  13. Avatar de 23JFK
    • |
    • permalink
    Ça ne semble pas franchement utile à l'ère de l'IDE tout puissant, ça serait même plutôt contre productif... Java découple déclaration et affectation, et lorsque l'on choisit de faire une ligne combinant déclaration et affectation, les IDE modernes complètent automatiquement la partie redondante de l'instruction. Par ailleurs, l'un des principes fondateurs de java c'est la rigueur du code et franchement, coller des var partout ne va pas aider à la lisibilité du code, ça risque même d'être une source d'erreurs avec des conversions implicites non désirées par le programmeur etc...
  14. Avatar de adiGuba
    • |
    • permalink
    @23JFK : il n'y aurait pas de conversion implicite.

    Il s'agit juste d'un sucre syntaxique pour raccourcir les déclarations de variable locale.

    a++
  15. Avatar de lvr
    • |
    • permalink
    Sans vraiment savoir ce qu'est le "erasure" ni le "reification" (je vais me documenter sur le sujet), sans me soucier de savoir si cette pratique est inspirée du langage x ou y, la question que je me pose est quel est le réel intérêt de cette modification ? De la concision ? La concision n'est pas souvent synonyme de lisibilité.
    J'ai le sentiment que Java a chopé le syndrome twitter : du code de plus en plus concis, virant à l’abréviation, et de moins en moins lisible et compréhensible.
  16. Avatar de adiGuba
    • |
    • permalink
    Citation Envoyé par lvr
    Sans vraiment savoir ce qu'est le "erasure" ni le "reification" (je vais me documenter sur le sujet), sans me soucier de savoir si cette pratique est inspirée du langage x ou y,
    Attention on a débordé du sujet : l'erasure et la reification concernent l'implémentation des Generics et non pas cette proposition de var/val.


    Citation Envoyé par lvr
    la question que je me pose est quel est le réel intérêt de cette modification ? De la concision ? La concision n'est pas souvent synonyme de lisibilité.
    J'ai le sentiment que Java a chopé le syndrome twitter : du code de plus en plus concis, virant à l’abréviation, et de moins en moins lisible et compréhensible.
    Oui c'est juste une proposition pour éviter de se répéter lors de la déclaration des variables locales.

    Grosso-modo :
    Code java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    var stringList = new LinkedList<String>();
    val aBigMap = new HashMap<String,List<Double>>();

    Serait strictement équivalent à :
    Code java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    LinkedList<String> stringList = new LinkedList<String>();
    final HashMap<String,List<Double>> aBigMap = new HashMap<String,List<Double>>();


    Bref ca va pas changer grand chose...



    a++
  17. Avatar de Gugelhupf
    • |
    • permalink
    Un langage faiblement typé peut utiliser les types Generics de Java via le raw-type sans soucis.
    Rien n'empêche aux autres de recréer leur propre implémentation sans utiliser les classes de la JRE.

    Oui mais là on est en dehors du langage...
    Java ne s'est jamais limité à du code, c'est un environnement.

    Et je ne parle même pas des problèmes que cela pose avec les lambdas !!! Bref je trouve que c'était vraiment une mauvaise idée (d'ailleurs celle-là C# ne l'a pas repris !)
    Oui, on ne peut pas forcément se servir de Function<T, R> pour tous les cas, mais tant pis. Avoir des checked-exception rend la signature plus clair. C# reprend tous les concepts cools, ils n'ont même pas l'équivalent d'un JCP (source), ou seulement depuis très récemment peut-être.

    Perso j'interdirais l'overload
    J'ai encore fait une confusion (overload/override , c'est pour ça que j'ai utilisé le terme "explicite" ). L'overload rend les choses compliqués lorsqu'on utilise des objets de même famille au niveau de la signature :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    meth1(Parent)
    meth1(ExtendsParent1)
    meth1(ExtendsParent2)
    En C# tu as overload + paramètre optionnel (cela aurait été mieux si cela avait été l'un OU l'autre).

    Ce que j'enleverais en Java par contre, ce n'est pas l'overload mais la création de méthode qui porte le même nom avec une casse différente :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    meth1()
    Meth1()
    mEth1()
    meTh1()
    etc
    Mis à jour 18/03/2016 à 12h20 par Gugelhupf
  18. Avatar de adiGuba
    • |
    • permalink
    Citation Envoyé par Gugelhupf
    Rien n'empêche aux autres de recréer leur propre implémentation sans utiliser les classes de la JRE.
    Oui (c'est ce que fait Scala .NET il me semble).
    Mais du coup tu perds la compatibilité avec les (nombreuses) API existante...


    Citation Envoyé par Gugelhupf
    Java ne s'est jamais limité à du code, c'est un environnement.
    Oui mais je m'étais limité au langage dans la discussion. Il y a des milliers de choses qui peuvent provoquer des incompatibilités...
    Mais assurer une compatibilité au niveau du langage c'est primordiale !!!


    Citation Envoyé par Gugelhupf
    Oui, on ne peut pas forcément se servir de Function<T, R> pour tous les cas, mais tant pis. Avoir des checked-exception rend la signature plus clair.
    Tu peux très bien déclarer une exception "non-checked" dans la signature, et c'est même une bonne chose.

    Je suis juste partisan du fait qu'il n'est pas nécessaire de devoir traiter une exception à tout prix.
    Bien souvent il est plus efficace de la laisser remonter le stacktrace... mais avec les checked-exception ce n'est pas toujours possible !
    La majorité du temps je traite une checked-exception en la faisant remonter dans une unchecked-exception...


    Citation Envoyé par Gugelhupf
    C# reprend tous les concepts cools, ils n'ont même pas l'équivalent d'un JCP (source), ou seulement depuis très récemment peut-être.
    Et il y a des avantages et inconvénients à cela : l'évolution du langage est plus rapide et plus dynamique... mais c'est aussi plus "bordélique" et moins poussé.

    Pour exagérer ca donne un peu l'impression : "vite c'est à la mode il faut le mettre dans le langage quoi qu'il arrive".

    Java est certes plus lent mais aussi plus mesuré dans son évolution.
    J'ai vu beaucoup de discussion sur des raisons de refuser des petits "hacks" simple et rapide car cela pouvaient poser des problèmes pour d'éventuelles évolutions futures...

    Il en résulte des choix plus poussé ou mieux adapté IMHO (enums, default-method/extension-method, delegate/functional interface).


    Citation Envoyé par Gugelhupf
    J'ai encore fait une confusion (overload/override , c'est pour ça que j'ai utilisé le terme "explicite" ). L'overload rend les choses compliqués lorsqu'on utilise des objets de même famille au niveau de la signature :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    meth1(Parent)
    meth1(ExtendsParent1)
    meth1(ExtendsParent2)
    Et si tu cumules cela avec des redéfinitions dans les classes filles cela peut devenir un gros merdier.

    Sans overload il aurait été possible d'avoir un type union : meth1(Parent|ExtendsParent1|ExtendsParent2) et donc vraiment une seule méthode.
    (c'est ce que fait Ceylon par exemple)

    Avec l'overload je pense que c'est très difficile à faire sans que cela ne pose d'autre problème...


    Citation Envoyé par Gugelhupf
    En C# tu as overload + paramètre optionnel.
    Les paramètres optionnel de C# correspondent à un simple sucre syntaxique plutôt crade car tout est défini à la compilation (grosso-modo le compilateur complète l'appel à ta place), cela implique pas mal de limitation :
    • Le changement d'une valeur par défaut n'est pas reporté tant qu'on ne recompile pas tous les codes appelant.
    • Si on redéfinie (override) la méthode en modifiant les valeurs par défaut, on peut avoir des comportements incohérents : x.Method() recevra des valeurs par défaut différente selon le type déclaré de l'instance.
    • Le simple fait de rajouter un paramètre par défaut va casser la compatibilité binaire. Il faut overloadé la méthode pour conserver une compatibilité (et cela peut vite devenir bordélique).


    Tout ceci est lié à l'overload des méthodes qui impose d'avoir le type des paramètres dans la signature.

    En gros si tu as ceci method(String arg1="default", int arg2=0, boolean test=false) alors le compilateur se chargera de définir les valeurs à ta place :
    Code java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    method(); // method("default", 0, false);
    method("a"); // method("a", 0, false);
    method("a", 10); // method("a", 10, false);
    la valeur par défaut est défini à la compilation et non pas lors de l'appel !


    Sans overload il serait possible de mettre en place un vrai système de paramètre par défaut, car les méthodes pourraient être être appelé simplement par leurs noms.
    En gros avec method() à la compilation on pourrait vraiment appeler la méthode sans aucun paramètre, et les valeurs par défaut seraient renseigner à l'exécution selon le type exact de l'instance...

    Mais bon pour ca il faudrait changer complètement le mécanisme d'invocation de méthode... et donc tout casser


    a++
  19. Avatar de Matthieu Vergne
    • |
    • permalink
    J'aime le côté explicite de Java, donc un tel mot clé ne me plaît pas, et la liste de problèmes en fin de billet explique pourquoi.
  20. Avatar de tomlev
    • |
    • permalink
    Citation Envoyé par bouye
    Et sinon C# est lui-même un plagiat de J# (toujours de Microsoft)
    Je ne sais pas où tu as pêché ça... J# est apparu après C#, et n'avait qu'un seul objectif : porter facilement du code Java vers .NET. Il n'y a pas de lien entre C# et J#, à part la plateforme cible.

    Citation Envoyé par bouye
    et donc de Java de toute manière

    Euh... certes, Java a été (avec C++) l'une des grandes inspirations de C# (modèle objet, machine virtuelle, garbage collector), mais même la toute première version de C# était déjà assez différente de Java pour qu'on ne puisse pas parler de plagiat. Par la suite, C# a évolué dans des directions différentes de Java (notamment sur les génériques), et généralement plus vite, si bien que c'est maintenant Java qui vient souvent piocher des idées dans C# (renvoi d'ascenseur en quelque sorte ). Les langages s'influencent mutuellement, et c'est très bien comme ça ; ce n'est pas du plagiat.
Page 1 sur 2 12 DernièreDernière