Le langage Ceylon passe en v1.1

Petit aperçu d'un langage plein de promesses

Un peu moins d'un an après la sortie de la v1.0, Ceylon gagne en maturité en passant en v1.1. « Voilà qui me fait une belle jambe, parce que je n'ai pas la moindre idée de ce qu'est "Ceylon" », me direz-vous avec perspicacité.

Eh bien, voilà une excellente occasion de le découvrir ensemble !

Présentation du langage de programmation Ceylon

Vers 2009, Gavin King, créateur de Hibernate et de JBoss Seam, se fit la réflexion que Java avait quand même quelques inconvénients, qu'il avançait peu[^avance] et qu'on pourrait sans doute faire un langage bien plus moderne.

Ainsi donc il s'allia à RedHat pour créer ce qui allait devenir Ceylon, un langage dont les concepts fondamentaux sont les suivants, si j'en crois les fonctionnalités clefs ainsi que l'introduction rapide :

Un langage multi-plateforme

Non seulement Ceylon est conçu pour être compilé pour la JVM et Javascript, mais en plus peut interagir nativement avec Java et Javascript.

Pourquoi un tel choix ? Pour plusieurs raisons :

  • Pour tourner sur n'importe quel OS possédant une machine virtuelle Java 7+ ou JavaScript.
  • Pour faciliter l'interopérabilité avec les énormes bases de code existant dans ces langages.
  • Parce que compiler en JavaScript permet d'avoir du code exécutable dans les navigateurs – et on a pas trop le choix du langage.
  • Parce que compiler pour la JVM permet de profiter de la performance, de la stabilité et de la fiabilité des JVMs et des outils associés.
  • Parce que Ceylon a été explicitement conçu comme un successeur de Java.

Exemples d'interopérabilité (tiré du site officiel, comme tous les exemples de cet article) :

Utilisation de Java dans Ceylon :

1
2
3
4
5
6
7
import java.util { HashMap }

value javaHashMap = HashMap<String,Integer>();
javaHashMap.put("zero", 0);
javaHashMap.put("one", 1);
javaHashMap.put("two", 2);
print(javaHashMap.values());

Utilisation de Javascript dans Ceylon :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
dynamic {
    dynamic req = XMLHttpRequest();
    req.onreadystatechange = void () {
        if (req.readyState==4) {
            document.getElementById("greeting")
                    .innerHTML = req.status==200
                            then req.responseText
                            else "error";
        }
    };
    req.open("GET", "/sayHello", true);
    req.send();
}

Fourni avec un SDK complet

Parce qu'un langage sans SDK ne sert pas à grand-chose, Celyon est fourni avec un SDK qui se veut complet et modulaire.

« Se veut » parce que pour l'instant, on peut remarquer deux inconvénients à ce SDK :

  1. Il manque encore certaines fonctionnalités (par exemple, le module de logs n'est arrivé qu'avec la v1.1).
  2. La majorité de ce SDK n'est disponible qu'avec Java, pas avec Javascript.

Modularité

Le code est organisé en package et en module, et est compilé sous forme de modules.

Qu'est-ce que cela implique concrètement ?

  • Qu'il est possible de déclarer des modules directement avec leurs dépendances, ce qui évite de maintenir un système de dépendances externes :
1
2
3
4
module org.jboss.example "1.0.0" {         
    import ceylon.math "1.1.0";
    import ceylon.file "1.1.1";
}
  • Qu'en cas de compilation vers Java, tout le module est compilé dans un seul fichier, avec des métadonnées compatibles avec les conteneurs OSGi et Vert.x. Mieux, ces modules sont chargés dynamiquement à l'exécution.
  • Qu'en cas de compilation vers JavaScript, le compilateur génère des modules au format CommonJS donc compatibles avec node.js et require.js.

Outre le fait que ce système de modules est un serpent de mer en Java (il est prévu pour Java 7 8 9), il offre souplesse, performance et compatibilité avec les systèmes existants. Et arrive avec un dépôt de modules centralisé, Ceylon Herd. Que demande le peuple ?[^panem]

Outils de développements

Comment imaginer un langage moderne sans IDE du même acabit ? RedHat fournit bien sûr des outils en ligne de commande, mais aussi un module Eclipse pour développer en Ceylon – lequel module est d'ailleurs développé par David Festal de la société SERLI, développeur et société françaises.

Un modèle 100% défensif

C'est pour moi une killer-feature de Ceylon et je m'étonne qu'elle ne soit pas plus mise en avant. Ceylon se protège au maximum contre les surprises, ce qui implique entre autres que :

  • Par défaut, tous les éléments sont privés. Il faut déclarer explicitement si on veut les voir ailleurs que dans leur propre bloc.
  • Par défaut, toutes les valeurs sont immutables. Si mon élément peut être modifié, il doit être explicitement déclaré comme variable : variable Integer count;
  • Par défaut, une valeur ne peut pas être null. Si une variable peut être nullable, ceci doit être déclaré explicitement. Adieu, NullPointerException !

Un petit exemple avec ce dernier point : String name = ... doit être défini et donc ne peut pas contenir null. Si j'ai besoin que mon nom puisse être indéfini, je dois le déclarer ainsi :

1
String? name = ...

Ce qui me permet d'écrire :

1
2
3
4
5
6
7
8
9
void hello(String? name) {
    if (exists name) {
        //name is of type String here
        print("Hello, ``name``!");
    }
    else {
        print("Hello, world!");
    }
}

Un système de type puissant

Le système de type gère l'union et l'intersection de types, les types énumérés et les alias de types. Mieux : Ceylon est capable d'inférence de type, laquelle inférence gère toutes ces subtilités !

Bien sûr, comme tout système puissant, il permet de faire des choses difficiles à comprendre. C'est donc à utiliser uniquement lorsque cela permet de rendre le code plus clair et plus efficace.

Alors là, je sens que j'ai perdu la plupart des lecteurs, donc je vais vous sortir des explications, des exemples, et des titres de niveau 3.

Union et intersection de type

Une union de types, c'est quand je veux dire qu'un élément est du type A ou du type B (ou inclusif). Exemple : mon élément est une personne ou une organisation :

1
Person | Organization personOrOrganization = ... ;

Une intersection de types, c'est l'autre opération logique : je veux dire qu'un élément est du type A et du type B en même temps. Exemple : mon élément est imprimable, a une taille et est persistant :

1
Printable & Sized & Persistent printableSizedPersistent = ... ;

Types énumérés

Les types énumérés me permettent de définir une série de sous-types et de faire des traitements différenciés sur chacun des sous-types, tout en permettant au compilateur de signaler qu'un des traitements est incomplet. L'exemple détaillé est un peu long alors je vous le mets en secret.

Imaginons que je veuille faire un traitement sur un arbre. Un arbre a des branches et des feuilles, que l'on regroupe sous le terme générique « nœud » :

1
abstract class Node() of Leaf | Branch {}

On fait un traitement quelconque sur ces nœuds. Le traitement différencie les feuilles des nœuds :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
Node node = ... ;
switch (node)
case (is Leaf) { 
    //node is of type Leaf here
    print(node.leafValue); 
}
case (is Branch) {
    //node is of type Branch here
    doSomething(node.leftNode);
    doSomething(node.rightNode);
}

Si demain je rajoute un troisième sous-type à mes nœuds, par exemple des fleurs ou des fruits, le compilateur va me signaler qu'il manque un bout du traitement à chaque fois que ce genre de switch est utilisé.

Alias de types

Il s'agit simplement de renommer un type : interface Strings => List<String>;

Inférence de type

En gros, il s'agit de permettre au compilateur de deviner le type réellement utilisé en fonction des informations dont il dispose. L'avantage pour Ceylon, c'est que couplé aux éléments précédents, il permet des inférences plutôt précises. Jugez plutôt : face à ceci :

1
value numbers = HashMap { "one"->1.0, "zero"->0.0, 1->1.0, 0->0.0 };

Le compilateur va déduire que le type de numbers est HashMap<String|Integer,Float> (un tableau associatif qui associe une chaîne de caractères ou un entier à un flottant).

Programmation orientée objet avancée

Non seulement en Ceylon tout est objet (y compris les nombres, la valeur null, les fonctions et les classes) ; mais en plus le langage supporte les fonctions d'ordre supérieur et les listes en compréhensions. Il supporte en plus une version restreinte de l'héritage multiple appelée mixin inheritance[^trad] – qui ressemble fortement à ce qui a été mis en place dans Java 8 d'ailleurs.

Là encore, on rentre dans la technique, alors voici quelques explications :

Les fonctions d'ordre supérieur

Une fonction d'ordre supérieur, en informatique, c'est une fonction qui prend une ou plusieurs fonctions en entrée ; ou (inclusif) qui renvoie une fonction.

Les détails nous entraîneraient très loin, aussi je vous propose l'article Wikipédia sur le sujet et l'implémentation Ceylon de la chose.

Les listes en compréhension

Une liste en compréhension est une liste dont le contenu est défini par le filtrage d'une autre liste. Par exemple, renvoyer la liste des adultes peut s'écrire :

1
[ for (p in people) if (p.age>=18) p ]

Là aussi les explications peuvent être longues, c'est pourquoi je vous renvoie à l'article Wikipédia et à l'implémentation en Ceylon.

… et bien d'autres choses !

Je pourrais encore parler par exemple de bien d'autres choses, comme :

Bref, vous l'avez compris : si vous désirez en savoir plus, vous devriez lire les fonctionnalités clefs de Ceylon, puis l'introduction à Ceylon. Enfin, lancez-vous dedans grâce au tour de Ceylon, qui suppose que vous avez quand même une connaissance minimale de la programmation orientée objet.

Ceylon, un projet 100% libre

Une des caractéristiques de Ceylon, c'est que le projet dans son intégralité est libre !

Pour commencer, le langage est intégralement spécifié, et la spécification est elle-même libre. Vous voulez créer un langage dérivé ? Allez-y !

Ensuite, l'implémentation standard est libre elle aussi. Tout comme le SDK. Et l'IDE. Et Herd, le gestionnaire de module. Et les sites qui y sont liés. Et la doc. Et tous les exemples. En fait, absolument tout est disponible sur Github !

La licence exacte dépend de ce dont vous parlez, la page de licence détaille ça mieux que moi.

Les nouveautés de la v1.1

Ah oui, parce que c'était le sujet de l'article à la base. Enfin, je pense que vous avez fini par comprendre que le véritable sujet ce cet article c'était de vous faire une présentation de Ceylon, mais la v1.1 m'a fourni un beau prétexte, alors voici quand même les nouveautés qu'elle apporte !

  • Des améliorations de performance. En particulier des temps de compilation, parce que le compilateur n'était pas spécialement nerveux.
  • La gestion des modules OSGi et l'intégration à Vert.x, qui permettent de créer des modules utilisables sur des plate-formes existantes et connues.
  • Des améliorations du SDK, avec l'arrivée de ceylon.promise, ceylon.locale et ceylon.logging. En voyant que les deux derniers n'existaient pas en v1.0, on se dit que le langage est vraiment jeune.
  • Un module de formatage de code pour l'IDE.
  • Plein de petits bugs.

Ceux que ça intéresse iront consulter la liste complète. Plus pour savoir ce qu'on peut corriger et améliorer dans un langage neuf que pour le contenu de la liste elle-même, j'imagine (et c'est d'ailleurs assez intéressant comme exercice).

Ceylon aujourd'hui

Voilà pour le tour d'horizon de Ceylon. Et si on prenait un peu de recul face à cette présentation quelque peu commerciale, et qu'on regardait ce qu'il en est aujourd'hui ?

Accueil

Ceylon a reçu un accueil assez mitigé. Parmi ceux qui ont un avis sur la question, on constate en gros deux positions :

  • Ceux qui considèrent que Ceylon est un excellent langage qui peut remplacer Java un peu partout, et donc est probablement le futur de Java s'il arrive à se lancer. Notez qu'on a déjà dit ça de Scala et de Groovy à leurs époques, pour ne citer que les deux plus connus, et pourtant Java est toujours bien vivant (même si ces deux langages ont trouvé leur public).
  • Ceux qui considèrent que Ceylon est un nième concurrent inutile à Scala ou Groovy et que les efforts sur Ceylon devraient plutôt porter sur ces langages. Mais c'est oublier les spécificités de Ceylon (support de la JVM et de JavaScript, approche défensive, …).

Comme d'habitude, la vérité est sans doute quelque part au milieu… Si on essaie de faire le bilan, que trouve-t-on ?

Avantages

  • L'approche défensive.
  • Le côté très carré qui va avec : le compilateur peut sortir un max d'erreurs.
  • Les variables qui ne peuvent pas être null par mégarde.
  • Le système de type, que je trouve un peu déroutant au premier abord mais qui semble ultra-pratique.
  • 100% libre !

Inconvénients

  • Le manque total de références. C'est le gros problème de Ceylon : on a pas encore de projet digne de ce nom en référence sur le site officiel, et le dépôt de modules reste plus ou moins vide.
  • Le support de JavaScript partiel. Les 2/3 du SDK n'existent tout simplement pas en JavaScript…
  • Le logo « Éléphant » est déjà pris par PHP !
  • Sans doute d'autres trucs qu'il faudrait plus d'usage pour s'en rendre compte.

Et maintenant ?

Eh bien voilà, je suis arrivé au bout de cette présentation. N'hésitez pas à dire ci-dessous, dans les commentaires, ce que vous en avez pensé.

Le plus simple est sans doute d'essayer par vous-même pour vous faire une idée, si vous avez un minimum de connaissances en programmation et en anglais :

Et puis, vous pouvez toujours tenter de faire le Javaquarium en Ceylon. Tiens, c'est une idée ça : je vais le faire !

Si vous aimez le futur et la programmation d'un langage, jetez un œil sur l'avenir du projet !

Ah j'oubliais : pourquoi « Ceylon » ? Parce que c'est l'ancien nom du Sri Lanka (Ceylan en français), que c'est proche de Java, et qu'on y produit pas mal de thé – boisson plus consommée dans le monde que le café…

Crédits

  • Les images (y compris l'icône) sont issues du site de Ceylon et donc sont sous licence CC-BY-SA 3.0 Unported.
  • Les codes d'exemples sont eux aussi du site de Ceylon et sont donc sous licence Apache Software Licence 2.0.

  1. C'était avant la sortie de Java 8, qui est sans doute la plus grosse avancée de Java de tous les temps depuis sa sortie. 

  2. Panem et circences, probablement. 

  3. Je n'ai pas la moindre idée de la traduction standard de ce terme, si tant est qu'elle existe. 


22 commentaires

Interessant…

Quelques commentaires :

Union et intersection de type

On appel ça des types de données algébriques il me semble, du moins au moins dans le monde fonctionnel.

D'ailleurs ce langage confirme la tendance actuelle d'introduire des concepts historiquement fonctionnels (données algébriques, list de comprehension, fonction d'ordre supérieurs, lambda, etc.) dans des langages et technos itérative à la base.

D'ailleurs ce langage confirme la tendance actuelle d'introduire des concepts historiquement fonctionnels (données algébriques, list de comprehension, fonction d'ordre supérieurs, lambda, etc.) dans des langages et technos itérative à la base.

Yep, Java 8 a fait la même récemment, à moindre échelle.

Merci pour l'article et la présentation de Ceylon.

A chaque langage son approche, et tant mieux.

En l'occurrence l'approche très défensive est tout à fait antagoniste de celle de Groovy où la visibilité des attributs est "public par défaut, en passant par des getters/setters s'ils sont définis, accès direct à la propriété sinon".

Pour l'intégration à Vert.x ça semble dans la logique des choses pour plusieurs raisons :

  1. Vert.x a pour principal objectif l'aspect polyglote, logique donc qu'il soit "opérable" dans autant de langage que la JVM en supporte

  2. Même si le projet est aujourd'hui sous la coupe d'Eclipse, il ne faut pas oublier que Tim Fox, son créateur, travaille désormais chez Red Hat (et plus chez VMWare). Forcément ça crée des liens.

Cela dit, il faudra attendre la version 3 de Vert.x pour avoir un support officiel du langage. Y'a quand même une grosse grosse dose de boulot avant qu'elle ne voit le jour (notamment au niveau des supports linguistiques : tout a été revu pour utiliser des générateurs de code plutôt que maintenir une API dans chaque langage). Mais c'est prometteur.

Et le système de gestion de dépendances de Ceylon trouvera certainement un grand intérêt dans ce genre de projets. C'est très séduisant comme moyen de déclarer les dépendances. Assez amusant de voir qu'on gravite beaucoup autour de la bonne solution pour la gestion de dépendances en Java, depuis Maven très déclaratif et plutôt lourd, à Ceylon purement déclaratif et "natif" en passant par Gradle et l'approche "que ce soit des dépendances ou des tâches, peu importe : ça se décrit tout au même endroit".

J'espère que Ceylon trouvera ses fans et surtout des cas d'utilisation (sa "niche", voire plus si affinités), le langage a l'air très intéressant.

+3 -0

Sinon à en croire les fonctionnalités principales, je vois pas trop la différence avec mon ami Python

Un typage très fort et donc très éloigné du "duck typing" de Python, pour commencer. Ce qui permet d'y brancher beaucoup d'outils qui font des tas d'automatisations dans tous les sens.

On appel ça des types de données algébriques il me semble, du moins au moins dans le monde fonctionnel.

Pas tout à fait dans le sens où les spécialistent distinguent les "types unions" des "types sommes" qui sont des types d'union dite "disjointe" où on sait pour chaque élément de quel côté de l'union on se trouve – ce qui n'est pas forcément possible en Ceylon avec X|Y si X et Y ne sont pas disjoints.

Les types unions et intersections sont intéressants pour permettre de typer certains styles de programme (ils sont dans Typed Racket pour permettre de typer des idiomes de Lisp non-typé), mais on peut généralement s'en passer quand on a les types algébriques et le filtrage de motif (c'est pour cela qu'on n'en ressent pas le besoin dans les langages ML). Ils compliquent pas mal le système de typage, et risquent de le rendre indécidable quand on les combine avec le polymorphisme ou le sous-typage. Comme je n'ai pas vu de spécification claire du système de typage de Ceylon (où est définie la relation de sous-typage ?), ou encore moins de preuve de sa correction, il est difficile de dire ce qu'il en est dans le cas de Ceylon.

Il faudrait éplucher la spécification pour avoir la réponse exacte. Par contre dans ce que j'ai lu, j'ai vu des passages sur la gestion de X|Y avec X et Y non disjoints et des problèmes que ça peut apporter.

Quant au reste, je connais très mal les langages fonctionnels et mal la théorie des langages, à vrai dire, donc je vais éviter de m'avancer là-dessus.

Contrairement à ce que dit son sous-titre (Say more, more clearly), la spécification de Ceylon n'est pas du tout claire sur le système de typage. Elle est très verbeuse (j'y ai déjà cherché la définition de la relation de sous-typage, et je n'ai pas trouvé) et, si la volonté était de pouvoir étudier ses propriétés, il aurait été plus judicieux de la formuler dans le format que les théoriciens du typage utilisent, à savoir un ensemble de règle d'inférences. Et si cette description existe quelque part (mais qu'on ne veut pas la mettre dans le document pour ne pas effrayer les programmeurs qui ne la connaissent pas), on pourrait mettre un lien au début de la partie "typage" de la spécification – son absence me fait penser qu'une telle description n'existe pas.

Il y a par contre des gens qui ont travaillé sur des morceaux du typage de Ceylon, en particulier Ross Tate qui a travaillé sur Kotlin et Ceylon. Mais c'est à chaque fois seulement des parties du système qu'il a étudié, et sans regarder plus dans les détails (ce qui a été fait et ce qui reste) il est difficile d'avoir de l'intuition sur si l'ensemble du système a une chance d'être correct ou non. Certains concepteurs du langage ont l'air d'avoir un avis très candide sur la question – ou en tout cas l'avaient en 2011 – mais je crois que Ross Tate a fait évoluer le système de typage dans la bonne direction.

Kotlin est à la mode un peu (beaucoup) grâce à JetBrains, ouais.

Après tout dépend de "ce genre de langages". Si tu fais référence à la JVM, ouais on peut dire ça. Après en tant que langage, Kotlin me semble plus proche de Scala que de Ceylon.

+0 -0

Alors dans ce sens là c'est le cas ouais.

Je dirais que Scala tient encore la première place en termes de popularité (toujours mis en premier en avant par Oracle, utilisé par Twitter, …) ?

J'ai l'impression que pas mal de gens utilisent Groovy (Netflix, …) même sans forcément trop le dire/savoir (à travers Gradle par exemple). A voir maintenant que ça a été repris par Apache. Le flottement suite à l'abandon par Pivotal a fait un peu mal à la confiance.

Et après y'a ceux que je ne saurais pas trop classé, dont Kotlin, Clojure, …

Je sais pas ce que t'en penses, ceux que t'as utilisés ou vus utilisés ?

+0 -0

Certain.

Ils sont à l'origine d'Hystrix en Java entre autres. Ou de Glisten en Groovy, ou encore de Asgard une interface web pour manager AWS.

Ils utilisent certainement aussi Node et bossent certainement aussi en JS. Mais à l'échelle d'une telle boîte, il est évident qu'ils utilisent plusieurs technos / langages. Le contraire serait très très étonnant.

+0 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte