Interact.jl, la nouvelle manière de réaliser des sites Web interactifs pour accéder à des codes de calcul

Julia est un langage de programmation principalement prévu pour des applications scientifiques, où la quantité de calculs à effectuer est très importante. D’habitude, ce genre de code s’écrit dans un langage assez statique, comme C, C++ ou Fortran, pour profiter de leur performance ; cependant, Julia se focalise sur une approche plus dynamique (comme Python ou MATLAB, plus prévus pour les interfaces que le calcul intensif) tout en gardant la performance à l’exécution. Julia arrive à rassembler ces deux côtés, la performance et la dynamicité.

Cet aspect dynamique a déjà été exploité pour créer des interfaces graphiques par le Web qui exploitent des codes de calcul. Par exemple, Escher.jl proposait de créer des interfaces composables, développées d’une manière similaire à Shiny en R. Ce paquet n’est plus maintenu depuis 2016 et n’a de remplaçant digne de ce nom que depuis peu, avec Interact.jl nouvelle génération (ce projet s’appelait InteractBase.jl jusqu’il y a peu avant d’être renommé et de remplacer l’ancien Interact.jl).

Ce nouveau paquet propose de créer des interfaces graphiques sur le Web pour des applications scientifiques. Il se construit par-dessus WebIO.jl, une couche d’abstraction pour l’interaction à travers les protocoles du Web : on peut ainsi développer un seul code pour l’utiliser dans un navigateur Web traditionnel (à travers le serveur Mux.jl), dans une application de bureau créée avec Electron (grâce à Blink.jl) ou encore dans Juno, l’environnement de développement de référence actuel pour Julia, ou IJulia.

Interact.jl utilise HTML5 et ses composants pour ses widgets, ce qui permet de couvrir facilement un grand nombre de fonctionnalités (sélection de couleur, de date, d’heure, de texte, etc.). Des frameworks CSS sont utilisés pour le style, qui est alors entièrement abstrait du code de l’interface : pour le moment, on peut utiliser Bulma et UIkit, mais aussi utiliser d’autres frameworks (UIkit a été ajouté en moins de deux cents lignes de code) ou encore intégrer son propre code CSS pour modifier un framework existant. Vue.js/.jl est utilisé pour la logique JavaScript et la synchronisation avec le script Julia.

Voir aussi : le tutoriel officiel, la liste des widgets disponibles, la documentation.

Sources : ANN: InteractBase, a redesign of Interact to create and style web apps in Julia, Sputnik project, second update.

Advertisements

Sortie de Julia 0.7 Alpha

Le langage de programmation Julia est prévu pour apporter les bienfaits en termes de productivité des langages dynamiques au monde extrêmement conservateur du calcul de haute performance. La première préversion Alpha du langage en version 0.7 est maintenant disponible et elle sera assez proche de la version 1.0. Elle contient toutes les fonctionnalités désapprouvées du langage, avec des avertissements (ces constructions donneront directement des erreurs avec Julia 1.0, prévue pour début août) : cette version 0.7 n’a que pour objectif de faciliter la transition de l’écosystème vers la 1.0. Les développeurs de Julia se sont inspirés des problèmes que Python a eu en passant de la version 2 à 3 : il sera possible, pour une très grande majorité des paquets, d’avoir un même code fonctionnel sur la version 0.6 (l’actuelle), la 0.7 ou sur la 0.7 et la 1.0.

La liste des changements par rapport à la version 0.6 est impressionnante : elle représente quatre-vingt cinq kilooctets de texte !

Syntaxe

Une bonne partie des changements de cette version vient de la syntaxe du langage. Ainsi, la syntaxe de définition des fonctions est plus flexible. Les arguments peuvent être déstructurés automatiquement par le langage : range((min, max)) = max - min définit automatiquement une fonction à un seul argument, range, cet argument étant un tuple. L’avantage est que, dans le code de la fonction, on peut utiliser chaque élément de ce tuple sans devoir le déstructurer soi-même : une fonction aussi simple peut être écrite en une ligne, en gagnant en lisibilité. Cette syntaxe se mélange sans aucun problème avec d’autres arguments :

foo((a, b), c) = (a + b) * c

Toujours dans les définitions de fonction, le conteneur d’arguments nommés (généralement, kw) est maintenant implémenté comme un tuple nommé (plutôt qu’une liste de paires). Ce conteneur apparaît lorsqu’une fonction ne définit pas tous ses arguments nommés : f(; kw...), par exemple. Les fonctions habituelles des dictionnaires fonctionnent alors naturellement : au lieu de devoir itérer dans toutes les entrées manuellement, on peut simplement utiliser haskey(kw, "arg"). Ceci n’est rendu possible que par l’implémentation des tuples nommés avec une excellente performance (qui a empêché cette manière de procéder jusqu’à présent). Petit supplément : une fonction peut maintenant marquer un argument nommé comme obligatoire, simplement en ne définissant pas sa valeur par défaut (ce qui peut être très utile pour la lisibilité du code).

L’objet missing sert désormais à représenter des valeurs manquantes (comme NULL en SQL ou NA en R, voire comme NaN pour le calcul en virgule flottante). Elle se propage naturellement dans les opérateurs et les fonctions mathématiques selon une logique à trois valeur (1 + missing == missing, par exemple). Cet objet a pour type Missing. Il peut simplifier très largement des parties de code qui utilisaient Nullable{T} comme type pour gérer des données qui pourraient manquer : le type de ces données devrait maintenant être Union{T, Missing}, ce qui est aussi clair ; dans le code, il n’est plus nécessaire d’utiliser des artefacts comme get(v) pour récupérer la valeur dans le cas où une valeur existe.

Aussi, la gestion des opérateurs a été dopée. Outre le nouvel opérateur de comparaison , quelques caractères de combinaison d’Unicode (primes, exposants, indices) peuvent se combiner aux opérateurs prédéfinis. Par exemple, on peut ainsi définir le nouvel opérateur de somme des carrés : +₂(a,b) = a^2 + b^2. Ces possibilités seront utiles à certains paquets effectuant des mathématiques de haut vol, en rapprochant la syntaxe de la notation mathématique usuelle. Fidèle à son habitude, Julia ne rate donc pas une occasion de gérer une plus grosse partie d’Unicode. Toujours pour les opérateurs, mais en mode mineur, l’opérateur paire => (utilisé pour définir des dictionnaires, par exemple) peut être diffusé sur des listes (.=>).

Pour l’appel des macros, il devient possible d’utiliser des crochets en plus des parenthèses : @macroname[args] correspond à @macroname([args]). Cette possibilité est prévue pour l’implémentation facile de nouveaux types de tableaux, par exemple des tableaux statiques (StaticArrays.jl) : il est plus naturel d’écrire @SArray[1 2; 3 4] que @SArray([1 2; 3 4]).

Les énumérations peuvent être définies dans un bloc begin-end, plutôt que de devoir être définies sur une seule ligne :

@enum Fruit begin
	apple=1 
	orange=2
	kiwi=4
end

Auparavant, il fallait impérativement écrire @enum Fruit apple=1 orange=2 kiwi=4, peu importe le nombre d’items.

La macro @isdefined permettra de déterminer si une variable locale est définie. Les tuples nommés, comme t=(a=1, b2=), font leur apparition : leurs champs peuvent être accédés par un numéro (t[1]) ou par un nom (t.a). De même, dans les fonctions générées (elles prennent en argument les types des arguments et génèrent un code hautement spécialisé), il devient possible de définir une fonction qui est à la fois générée et non générée (pour une implémentation non spécialisée) en utilisant la macro @generated pour délimiter les parties générées des autres.

Certaines syntaxes sont désapprouvées, en vue de leur assigner une nouvelle signification plus tard. Par exemple, begin ne peut plus apparaître dans une indexation : dans le futur, a[begin] pourrait sélectionner le premier item d’un tableau (tout comme a[end] sélectionne le dernier élément). Il n’est plus possible d’effectuer d’assignation au niveau d’une indexation : x[i=1] sélectionnait l’élément 1 du tableau et définissait une variable i (certains utilisaient cette possibilité pour se rapprocher de leurs habitudes en C, comme a[i += 1] pour sélectionner l’élément courant et incrémenter i) ; bientôt, cette syntaxe pourrait être récupérée pour passer des arguments nommés lors de l’indexation, ce qui serait utile pour la lisibilité de certains types de tableaux (notamment bidimensionnels : on pourrait écrire a[x=1, y=2], comme xarray en Python).

Bibliothèque standard

Le gestionnaire de paquets précédent, Pkg2, était un reliquat de Julia 0.2. Il avait un certain nombre de limitations, notamment pour indiquer des dépendances conditionnelles entre modules (par exemple, pour des fonctions dont leur seul objectif est de faciliter l’utilisation conjointe de deux modules). La description des paquets se faisait par une myriade de petits fichiers (quelques octets), ce qui faisait rapidement une performance horrible selon le système de fichiers ; en particulier, une version est décrite par un identifiant de commit Git, ce qui impose de cloner le dépôt Git d’un paquet pour l’installer (y compris tout l’historique, même s’il est très gros), puis d’utiliser Git pour vérifier la version installée (ce qui est d’une lenteur abyssale). Ces caractéristiques étaient très intéressante dans le cas d’un écosystème en plein boom et où la proportion d’utilisateurs qui ne contribuent pas à de nouveaux paquets est assez faible, mais plus à un langage qui se veut utilisable par le plus grand nombre. Pkg3 évite ces écueils en repartant de zéro pour la description et l’installation de paquets. Le dépôt de paquets actuel est bien sûr importé directement dans celui de Pkg3 (une liste modérée des “meilleurs” paquets sera aussi disponible). Pkg3 gère aussi la notion d’environnement, c’est-à-dire un ensemble de paquets et de versions que l’on peut échanger rapidement (comme les environnements virtuels de Python).

Le protocole d’itération a complètement changé avec cette version, notamment en exploitant le travail effectué pour intégrer missing dans le langage avec une bonne performance. Auparavant, il fallait implémenter trois fonctions différentes : start pour déterminer l’état initial de l’itérateur, next pour récupérer l’élément courant et le prochain état, done pour indiquer si l’état est final. Maintenant, il n’y a plus que la fonction iterate : avec un seul argument (l’itérateur), elle doit retourner l’état initial et le premier élément ; avec deux arguments (l’itérateur et l’état), elle doit retourner le prochain élément et le prochain état… ou nothing si l’itérateur n’a plus d’éléments dans la collection.

La bibliothèque mathématique de Julia est en cours de réécriture : elle était écrite entièrement en C (openlibm), en repartant du code de FreeBSD et d’OpenBSD, mais avait ses limitations. Notamment, si une implémentation d’une fonction spéciale (logarithme, exponentielle, sinus, etc.) est fournie, elle ne vaut que pour un seul type ; si elle était écrite en Julia, la même implémentation pourrait être utilisée avec d’autres types (nombre à virgule flottante sur trente-deux ou soixante-quatre bits, voire à précision infinie, par exemple). La charge de maintenance est identique (le projet Julia doit toujours maintenir sa propre bibliothèque mathématique, celles des compilateurs n’étant pas toujours au niveau), mais les avantages sont présents — notamment celui de diminuer la barrière d’entrée pour les nouveaux contributeurs. Ce travail est toujours en cours.

Parallélisme en mémoire partagée avec Julia

Julia est un langage de programmation prévu pour le calcul scientifique tout d’abord, même s’il se généralise de plus en plus, notamment pour les interfaces graphiques (InteractBase.jl, par exemple). Il cherche à obtenir le meilleur des deux mondes : celui des langages pour le calcul intensif (C, C++, Fortran…), où la performance est le critère le plus important, ainsi que celui des langages dynamiques (Python, LISP…), bien plus pratiques pour le développement.

Dès 2015, les premières expériences pour apporter le parallélisme à mémoire partagée ont donné naissance à la construction @threads : il devient alors très simple de lancer toutes les itérations d’une boucle donnée en parallèle. Cette manière de procéder correspond à ce qui est le plus souvent fait dans le calcul intensif (elle correspond à OpenMP, par exemple). Son implémentation force à repenser certaines parties de l’implémentation de Julia, afin de s’assurer que toutes les parties du code fonctionnent de manière sécurisée en parallèle : le ramasse-miettes, la génération du code, etc.

Cependant, cette construction est très limitée : elle ne s’adresse qu’aux cas où le même code est exécuté sur des parties de données différentes (parallélisme de données). Ce paradigme correspond très bien au fonctionnement des processeurs graphiques, mais pas à la totalité des applications, qui ont besoin d’un modèle de fils d’exécution plus précis. Par exemple, il n’était pas possible de lancer le code de calcul dans un fil d’exécution séparé de l’interface graphique — cette dernière devait être figée pendant l’exécution des calculs. Bien que limitée, elle s’est montrée très efficace en pratique : Celeste.jl est un moteur d’inférence à base d’images astrophysiques qui a pu être exécuté sur un superordinateur, en développant une puissance de calcul de plus d’un téraflops.

L’approche en cours de développement sera similaire à celle de Cilk (un dérivé de C développé au MIT), avec trois types principaux de construction : spawn pour lancer un fil d’exécution, sync pour en attendre les résultats et parfor pour paralléliser simplement une boucle. Ce paradigme est à la fois très puissant (toutes les fonctionnalités sont disponibles pour implémenter toute logique parallèle) et très simple (ce qui garantit une certaine productivité pour écrire le code et diminue le risque d’erreurs).

Néanmoins, cette manière d’écrire des programmes parallèles pose très vite des questions d’implémentation très pratiques : que faire en cas de parallélisme imbriqué (ou composé) ? Que se passe-t-il lorsqu’un code parallèle appelle une bibliothèque qui exploite elle-même le parallélisme ? En général, ces bibliothèques sont très bien écrites et profitent énormément des capacités parallèles (comme BLAS pour les opérations d’algèbre linéaire), mais la majorité des implémentations actuelles (OpenMP, Cilk…) ne permettent de paralléliser que la boucle extérieure, tandis que toutes les boucles intérieures sont exécutées en série (ce qui inclut les bibliothèques extérieures, de manière générale).

Julia envisage de fonctionner de manière différente, avec un ordonnancement en profondeur. La majorité des systèmes actuels utilisent le “vol” de tâches : quand un fil d’exécution a terminé toutes ses tâches, il prend le travail d’autres fils qui n’ont pas encore fini. Le problème est qu’il faut donc stocker une liste de toutes les tâches pour chacun des fils d’exécution, ce qui peut représenter une grande quantité de mémoire. Au contraire, l’ordonnancement en profondeur a d’excellentes garanties théoriques (pas besoin de stocker de grandes piles de tâches à exécuter pour chaque fil d’exécution) et, en pratique, a toutes les propriétés requises pour exploiter au mieux les caches des processeurs. Les fils d’exécution ne décident pas eux-mêmes des tâches à exécuter, puisqu’un contrôleur central s’en charge. Cependant, il n’en existe, pour le moment, aucune implémentation utilisable en production, seulement quelques codes de recherche.

Le code pour ce faire en Julia (partr) est en cours de développement depuis plus d’un an et utilise la notion de coroutine pour l’implémentation des tâches. Certaines fonctionnalités sont d’ores et déjà implémentées

Source : Shared memory parallelism in Julia with multi-threading.

Du neuf sur Julia 0.7

Julia, le langage de programmation orienté calcul scientifique moderne (aussi simple à utiliser que Python ou MATLAB, aussi performant que Fortran ou C++), n’est pas un grand habitué du respect des dates : l’arrêt des fonctionnalités pour la version 1.0 était prévu pour la mi-décembre… mais ce n’est toujours pas le cas à la mi-mars ! Comme depuis longtemps, cette version est annoncée pour “bientôt” : pendant ce temps, les développeurs peaufinent le langage et son environnement, pour qu’il soit aussi agréable que possible dès le premier jour de la 1.0. C’est aussi pour cela que la version 0.7 sortira plus tôt : elle contiendra toutes les nouveautés de la 1.0, avec quelques couches de compatiblité avec les précédentes versions.

Un très gros point bloquant pour le moment est la réécriture complète de l’optimiseur de Julia. En effet, pour atteindre un très haut niveau de performance, l’implémentation du langage utilise un moteur de compilation très performant (LLVM, aussi derrière Clang ou Flang), couplé à une série de passes d’optimisation spécifiques à Julia. Les dernières versions de Julia ont profondément modifié certains aspects du système de type, notamment pour gérer les valeurs manquantes dans les tableaux de données : au lieu d’un type spécifique, elles sont maintenant représentées par une union (soit rien, soit une valeur d’un type donné). De plus, le protocole des itérateurs change complètement, notamment pour être plus simple à implémenter : il se réduit à une fontion iterate de l’état courant, qui renvoie soit rien (s’il n’y a plus d’élément suivant), soit un nouvel état et la valeur associée — soit le même genre d’union que pour les valeurs manquantes. Cependant, la passe d’optimisation précédente était incapable de générer du code décemment rapide pour ces cas particuliers : pour garder une bonne performance, la réécriture était nécessaire.

Ce retard dû à l’optimiseur laisse du temps pour travailler sur d’autres points, notamment la gestion des tableaux. D’autres points restent toujours en suspens : moins importants (ils ne risquent pas de casser du code existant), ils pourront être intégrés par la suite, dans le cycle de vie de Julia 1.x. La vitesse de compilation en fait partie.

La gestion des paquets est aussi un chantier pour la première version stable à long terme de Julia. Elle est actuellement prise en charge par Pkg2, un utilitaire développé du temps de Julia 0.1 et qui commence à montrer ses limites : par exemple, pour les dépendances, il n’est possible que d’indiquer des dépendances dures. Impossible de représenter une dépendance à l’un d’une série de paquets (on souhaite simplement qu’au moins un des paquets de cette liste soit installé) ou des fonctionnalités conditionnelles (activer certaines fonctionnalités d’un paquet quand un autre est installé). La principale barrière au déploiement de la nouvelle version du gestionnaire de paquets, la bien nommée Pkg3, est qu’elle n’est compatible qu’avec les préversions actuelles de Julia 0.7… et que peu de paquets sont compatibles. Il manque aussi l’expressivité des versions requises pour l’installation d’un paquet (au moins telle version jusque telle autre en excluant une troisième, par exemple). Énormément d’architecture est déjà en place, comme la conversion automatique des descriptions de paquets au nouveau format : le grand jour, il sera possible de proposer automatiquement à tous les projets enregistrés dans le gestionnaire de paquets une description au nouveau format.

Sources : 1.0 progress/status, Pkg3 plan and status.

Les fonctionnalités de Julia 1.0 seront arrêtées le 15 décembre

Julia est un langage de programmation de haut niveau, dynamique, mais orienté applications de haute performance (surtout pour le calcul scientifique). Malgré son jeune âge (il est apparu pour la première fois au grand public en 2012), il a déjà réussi à fédérer une certaine communauté (on estime à 250 000 son nombre d’utilisateurs en 2017).

Il s’apprête à voir sa première version finale, numérotée 1.0, après de longues années de développement. Toutes les fonctionnalités ne sont pas encore implémentées, mais cela ne devrait tarder : plus aucune ne sera acceptée dès le 15 décembre. À cette date, la première préversion Alpha de la 0.7 sera disponible, six mois après la 0.6. Julia 0.7 et 1.0 devraient être disponibles dans deux mois, si tout va bien.

Bon nombre d’évolutions attendues font leur apparition, comme la macro @isdefined pour déterminer si une variable locale existe ou encore un conteneur de type dictionnaire pour les arguments passés par nom à une fonction (en réalité, des tuples nommés, une autre nouveauté). Les valeurs manquantes, très utilisées en science des données, font leur apparition au sein même du langage (auparavant, elles l’étaient dans les paquets qui en avaient besoin). La macro @nospecialize est utilisée pour indiquer que le compilateur ne peut pas spécialiser une fonction sur le type d’un argument.

Certaines constructions peu lisibles ne sont plus acceptées dans le langage : 1.+2 pouvait être compris comme la somme d’un nombre à virgule flottante (1.) et d’un réel (2) ou bien comme la somme élément par élément entre listes (d’un côté, 1, de l’autre, 2 : 1 .+ 2) ; la juxtaposition de nombres en notation binaire, octale et hexadécimale ne pouvait être qu’illisible (0xapi était compris comme 0xa * pi). La bibliothèque standard a été considérablement allégée, en suivant un mouvement lancé depuis belle lurette : les fonctionnalités moins souvent utilisées (ou qui mériteraient d’être mises à jour plus souvent que le compilateur) ont été déplacées dans des paquets.

La sortie de la version 1.0 se fera en deux temps : tout d’abord, la version 0.7, qui aura exactement les mêmes fonctionnalités, mais avec des avertissements pour ceux qui utiliseraient d’anciennes syntaxes maintenant déconseillées ou supprimées ; très rapidement après, la 1.0, expurgée de ces messages. Ainsi, il sera conseillé de migrer son code vers la version 0.7 pour profiter des messages d’avertissement plus nombreux ; ensuite, le passage à la 1.0 se fera instantanément. Pour les nouveaux, par contre, seule la version 1.0 sera mise en avant.

Toutes les fonctionnalités souhaitées pour Julia 1.0 ne sont pas encore implémentées, toutefois. Si les développeurs ont le temps, tout ce qui sera possible sera implémenté d’ici au 15 décembre, pour laisser le temps aux tests avant la version finale. Les autres fonctionnalités seront ajoutées lors du cycle de vie de Julia 1.x, quitte à laisser des syntaxes indésirables acceptées : elles ne seront supprimées que lors du passage à Julia 2.0.

Voir aussi : la liste des changements apportés jusqu’à présent à Julia 0.7.0.

Source : 1.0 Feature Freeze Dec 15th.

Sortie de Julia 0.6

Julia est un langage de programmation de haut niveau, dynamique, mais orienté applications de haute performance (surtout pour le calcul scientifique). Malgré son jeune âge (il est apparu pour la première fois au grand public en 2012), il a déjà réussi à fédérer une certaine communauté (on estime à 250 000 son nombre d’utilisateurs en 2017), dans bon nombre de domaines.

Sa version 0.6 est sortie, un peu moins d’un an après la précédente. Elle marque le dernier jalon avant la version finale : la 0.7 et 1.0 sortiront presque simultanément, la seule différence étant la gestion d’anciennes syntaxes et l’émission de messages correspondants pour la 0.7 (ce dont la 1.0 ne s’alourdira pas).

Le plus gros changement de Julia 0.6 concerne le moteur d’inférence des types, qui a été complètement réécrit pour être plus rapide, donner des résultats plus précis (ce qui permet d’optimiser le code exécuté) et permettre de nouvelles fonctionnalités. Ainsi, en définissant un nouveau type avec des paramètres (comme une classe générique dans bon nombre d’autres langages), on peut faire référence aux types des paramètres précédents. Par exemple, avec struct Foo{R<:Real, A<:AbstractArray{R}}, on définit un type Foo par rapport à un type particulier de nombres réels (comme Float64) et un tableau (dont les éléments doivent avoir le même type que mentionné précédemment).

Au niveau syntaxique, les mots clés pour définir des types ont été changé pour promouvoir par défaut des valeurs immuables : le code généré est bien souvent plus rapide, cela réduit le risque d’erreur lors de l’écriture du code, avec un impact souvent minime sur l’utilisateur. Ainsi, type devient mutable struct tandis que immutable devient simplement struct.

Pour la performance, les opérateurs et fonctions sont tous vectorisés automatiquement à l’aide d’un point : a .⨳ b est la syntaxe équivalente à l’application de l’opérateur  entre tous les éléments de a et de b. L’avantage principal est que ce mécanisme est géré au niveau du langage, il n’y a plus de traitement particulier des opérateurs vectorisés. Grâce à ce changement, l’écriture de code très optimisé sur des vecteurs devient très facile : pour évaluer une expression utilisant une série d’opérateurs vectorisés, Julia n’exécute qu’une seule boucle à travers les opérandes.

Voir aussi : les notes de version de Julia 0.6.

Sortie de Julia 0.5

Julia est un langage de programmation assez récent (son développement a commencé en 2012), mais il a déjà réussi à attirer une assez grande communauté autour de lui. Initialement, il est prévu pour le calcul scientifique, en fournissant un langage dynamique et facile à utiliser (comme Python ou MATLAB) tout en gardant une très bonne performance (digne d’un langage compilé : Julia est très proche du C ou du Fortran dans les temps d’exécution).

La version 0.5 vient de sortir, un an après la précédente… et avec pas loin de trois mois de retard sur le programme. Elle ne se focalise pas exclusivement sur la performance, mais plutôt sur les fonctionnalités : certains changements syntaxiques préparent le terrain pour des améliorations de performance pour les prochaines versions du langage. Ses développeurs cherchent à stabiliser le langage dès que possible pour favoriser son adoption : la première version finale, la 1.0, ne devrait plus tarder (courant 2017).

Dans les nouveautés intéressantes pour bon nombre de programmeurs, les expressions de la forme f(i) for i in 1:n sont maintenant des génératrices : elles correspondent à des itérateurs sur les valeurs demandées. Ainsi, pour calculer la somme de toutes ces valeurs, il n’est plus nécessaire de créer un tableau à cette occasion : sum(f(i) for i in 1:n) au lieu de sum([f(i) for i in 1:n]) précédemment (les crochets ne sont plus nécessaires). Toujours au niveau des génératrices, il devient possible d’ajouter des conditions avec le mot clé if et d’effectuer des boucles imbriquées en utilisant plusieurs fois for.

Les opérateurs avec point existent depuis un certain temps et servent à effectuer une opération sur chaque élément séparément (par exemple, a .+ b effectue la somme de chaque élément de a et de b). Désormais, ce point est généralisé pour toutes les fonctions ; l’interpréteur se charge alors d’appeler la fonction broadcast. Dans le futur, ces nouvelles possibilités syntaxiques seront utilisées pour optimiser le code, en fusionnant ces opérations.

Julia étant prévu pour le calcul scientifique, le parallélisme est une thématique très importante. Certaines facilités syntaxiques existent déjà depuis longtemps pour la communication entre processus, mais les développeurs cherchent depuis un certain temps la meilleure approche pour la programmation multifil (c’est-à-dire à mémoire partagée). Les idées convergent vers une implémentation disponible dès cette version 0.5, mais la syntaxe pourrait encore évoluer. Pour exploiter les différents cœurs d’une machine, il suffirait d’utiliser une macro @threads sur chaque boucle à paralléliser, sans plus d’action requise de la part de l’utilisateur.

Un débogueur fait maintenant son apparition dans Julia. Il n’est pas livré avec l’interpréteur, mais est très facile à installer. Gallium est en développement depuis de nombreux mois et est aussi intégré dans l’environnement de développement Juno.

Cette version regorge de modifications en tout sens pour donner plus de cohérence à la bibliothèque standard et pour alléger son cœur (de telle sorte qu’il reste possible d’utiliser Julia dans n’importe quelle situation). Ces optimisations sont, par exemple, utiles dans l’embarqué ; à ce sujet, l’exécution sur des plateformes ARM (généralement utilisées dans l’embarqué) a été largement améliorée ; de même, l’architecture IBM POWER est maintenant gérée.

Source : Julia v0.5.0 Release Notes.