URL: https://linuxfr.org/news/ocaml-4-04-et-4-05 Title: OCaml 4.04 et 4.05 Authors: chicco octachron, Yves Bourguignon, kantien, palm123, Davy Defaud, Snark, Benoît Sibaud, claudex, gasche, Ontologia, patrick_g, Dinosaure et Lucas Date: 2016年11月10日T13:34:18+01:00 License: CC By-SA Tags: ocaml et barbara_liskov Score: 39 La version 4.05.0 du langage OCaml vient d’être publiée, le 13 juillet 2017 ; quelque mois après la sortie de la version 4.04.0, annoncée le 4 novembre 2016. OCaml est un langage fonctionnel de la famille des langages ML (dont font partie [SML](https://en.wikipedia.org/wiki/Standard_ML) et [F#](https://fr.wikipedia.org/wiki/F_sharp)). Il s’agit d’un langage fonctionnel multi‐paradigme fortement typé qui permet de mélanger librement les paradigmes fonctionnel, impératif et objet. ![LOGO](https://ocaml.org/img/colour-logo-white.svg) Il s’agit des deux premières versions après le passage à un cycle court de développement (6 mois). Elles contiennent assez peu de changements majeurs et peuvent être considérées comme des versions de maturation, en particulier pour la nouvelle phase d’optimisation Flambda introduite dans la version 4.03. On note cependant l’intégration de deux nouveaux outils dans le compilateur : un profileur de mémoire et un _fuzzer_ ; mais aussi quelques améliorations du langage et de la bibliothèque standard. Pas mal de changements ont aussi eu lieu dans les entrailles du compilateur et n’ont pas encore débouché sur des changements visibles à la surface du langage. Une des nouveautés les plus surprenantes de ces cycles de développement est probablement l’apparition d’une nouvelle syntaxe alternative à OCaml, nommé Reason(ml), sous l’impulsion d’une équipe de Facebook. ---- [Site officiel](http://ocaml.org/) [Discours officiel](https://discuss.ocaml.org/) [Manuel OCaml : spacetime, profileur de mémoire](https://caml.inria.fr/pub/docs/manual-ocaml/spacetime.html) [Manuel OCaml : afl-fuzz](http://caml.inria.fr/pub/docs/manual-ocaml/afl-fuzz.html) [Manual OCaml : exceptions locales](https://caml.inria.fr/pub/docs/manual-ocaml/extn.html#sec258) [Reason](https://facebook.github.io/reason/) [Annonce officielle de la 4.05](https://sympa.inria.fr/sympa/arc/caml-list/2017-07/msg00058.html) [Annonce officielle de la 4.04](https://sympa.inria.fr/sympa/arc/caml-list/2016-11/msg00010.html) [Dépêche LinuxFr.org sur OCaml 4.03](https://linuxfr.org/news/ocaml-4-03) ---- # Outils de développement Du côté des outils de développement, deux nouveaux outils ont été intégrés à la distribution OCaml: un profileur de mémoire, Spacetime, et un fuzzer, afl-fuzzer. ## Spacetime: profileur de mémoire Le nouveau profileur de mémoire baptisé spacetime n’est pas activé par défaut à cause de son impact sur la performance et la mémoire des processus profilés. Il est cependant aisément disponible à travers un _switch_ opam, le gestionnaire de paquets d’OCaml qui gère aussi les versions installées du compilateur Ocaml. Installer un compilateur OCaml avec le prise en charge de spacetime activée se fait avec une simple ligne : ```bash $ opam switch 4.05.0+spacetime ``` Une fois spacetime activé, n’importe quel programme peut être profilé en définissant la variable d’environnement `OCAML_SPACETIME_INTERVAL`. On peut, par exemple, s’intéresser à la consommation mémoire lors de l’analyse des dépendances du compilateur : ```bash $ OCAML_SPACETIME_INTERVAL=50 codept ocaml-compiler ``` Les traces sont ensuite sauvegardées sous la forme `spacetime-$process-id` et peuvent être analysées grâce à l’outil `perf_spacetime` qui dispose d’un mode terminal et d’un mode service Web permettant d’explorer en détails la consommation mémoire. ![Mémoire consommée](http://pix.toile-libre.org/upload/original/1493718413.png) Dans le cas illustré, on peut voir que la consommation de la mémoire se structure en cycles composés d’une phase d’exploration durant laquelle la consommation de la mémoire croît, suivie d’une phase de résolution qui permet au ramasse‐miettes de collecter la majorité de la mémoire utilisée dans la phase précédente. ## Intégration de afl-fuzzer _American fuzzy lop_ (aussi connu sous le nom de afl-fuzzer) est un fuzzer, c’est‐à‐dire un outil pour tester des logiciels en leur injectant des données aléatoires en entrée. Contrairement à la plupart des _fuzzers_, _afl-fuzzers_ va plus loin que la simple injection de données aléatoires non corrélées : il observe le comportement interne du programme testé pour essayer de forger des données d’entrée qui vont explorer de nouvelles branches du code à éprouver. Cela permet d’améliorer le taux de couverture du test, au prix d’une nécessaire instrumentation du code. La mouture 4.05 d’OCaml permet désormais d’ajouter cette instrumentation au code compilé grâce à une simple option de compilation. Comme exemple basique d’utilisation, on peut considérer ce code qui échoue sur un cas très particulier : ```OCaml let () = let s = read_line () in if String.length s> 5 then match s.[0], s.[1], s.[2], s.[3], s.[4] with | 'e', 'c' , 'h', 'e', 'c' -> failwith "Échec improbable" | _ -> () ``` Pour analyser ce code avec _afl fuzzer_, il suffit d’utiliser la nouvelle option `-afl-instrument` d’_ocamlopt_, fournir quelques cas de base, puis de lancer _afl-fuzz_ lui‐même, qui va utiliser un algorithme générique sur ces cas de base pour générer de nouveaux cas à tester : ``` ocamlopt -afl-instrument test.ml afl-fuzz -i input -o output ./test.ml ``` Ce dernier trouve rapidement que, par exemple, `echec#Ε5ドル<ȹpu|Ϧģ` fait planter le programme. Cependant, il n’est pas assuré de trouver une entrée minimale (ici « echec ») faisant échouer le programme. # Évolution du langage OCaml ## Exceptions locales Parmi les particularités d’OCaml, il y a ces exceptions qui sont suffisamment rapides pour être utilisées en tant que structures de contrôle. OCaml 4.04 introduit une notation simplifiée pour les exceptions locales : ```OCaml let recherche_premier (type a) predicat table= let exception Trouve of a in try Array.iter (fun x -> if predicat x then raise (Trouve x) ) table; None with Trouve x -> Some x ``` Avant l’introduction de cette nouvelle notation, il fallait passer par un module local pour définir l’exception : ```OCaml let recherche_premier (type a) predicat table= let module M = struct exception Trouve of a end in try Array.iter (fun x -> if predicat x then raise (M.Trouve x) ) table; None with M.Trouve x -> Some x ``` De plus, dans le futur, ces exceptions locales pourraient faire l’objet d’optimisations spécifiques. ## Ouverture locale de module dans les motifs Une des nouveautés d’OCaml 4.04 est la possibilité d’ouvrir localement un module à l’intérieur d’un motif : ```OCaml module M = struct type t = A | B | C type u = List of t list | Array of t array end let est_ce_la_liste_ABC x = match x with | M.( List [A;B;C] ) -> true | _ -> false ``` Comme dans le cas des expressions, ouvrir localement un module permet d’importer les types et valeurs dans la portée (_scope_) courante sans polluer la portée en dehors du motif. Cette construction permet également de rétablir une certaine symétrie entre motifs et expressions, comme dans l’exemple suivant uniquement valide depuis OCaml 4.04 : ```OCaml module N = struct type r = { x : int } end let N.{ x } (* { x } est un motif ici *) = N.{ x = 1 } (* { x = 1} est une expression de ce côté-ci *) ``` ## Représentation en mémoire optimisée Il est désormais possible d’optimiser la représentation en mémoire des variants avec un seul constructeur et un seul argument ou des enregistrements avec un seul champ en les annotant avec `[@@unboxed]` : ```OCaml type 'a s = A of 'a [@@unboxed] type 'a r = { f: 'a } [@@unboxed] ``` Sans l’annotation `[@@unboxed]`, ces deux types seraient représentés en mémoire sous la forme d’un bloc OCaml composé d’un en‐tête et d’un champ : ``` ┌────────┬───────────┐ │ entête │ champs[0] │ └────────┴───────────┘ ``` Pour des types plus complexes, l’en‐tête contient des informations sur le nombre de champs dans le bloc et sur l’étiquette du constructeur. Cependant, pour ces cas particuliers, l’en‐tête n’apporte aucune information et il est possible de l’élider. Cette optimisation est particulièrement utile dans le cadre des types algébriques généralisés, puisqu’elle permet d’introduire des types existentiels sans payer de coût en mémoire. Par exemple, si l’on souhaite oublier le type des éléments d’une liste, on peut introduire le type algébrique généralisé suivant : ```OCaml type liste = Any: 'a list -> liste [@@unboxed] ``` Grâce à l’annotation `[@@unboxed]`, le type `liste` aura exactement la même représentation en mémoire qu’une liste classique, et représente une version du type `'a list` qui interdit toute manipulation dépendante du type `'a` des éléments de la liste. Dans la plupart des cas, cette optimisation est transparente à l’usage. Cependant, les bibliothèques de liaison (_bindings_) C‐OCaml doivent faire attention à ce changement de représentation en mémoire. Afin d’éviter de briser les bibliothèques de liaison existantes, cette optimisation n’est pas activée par défault, mais doit l’être au cas par cas avec l’annotation`[@@unboxed]` ou via l’option de compilation `-unboxed-types`. ## Vers des chaînes de caractères immuables La migration vers des chaînes de caractères immuables, initiée dans OCaml 4.02, se poursuit avec l’apparition d’une option de configuration du compilateur permettant d’en faire le comportement par défaut. Cette option n’est pas encore activée par défaut dans 4.05, mais des discussions sont en cours pour l’activer dans la prochaine version (4.06). ## Évolution de la bibliothèque standard La bibliothèque standard continue d’évoluer doucement, soit pour pallier des incohérences, avec par exemple l’introduction d’une fonction `map` pour les ensembles `Set`, soit pour s’adapter à l’évolution du code idiomatique OCaml, avec par exemple l’ajout de variantes de fonctions utilisant des options plutôt que des exceptions pour gérer les éléments manquants dans des `Set` ou des `Map`. # Amélioration du compilateur Ces deux cycles de développements auront vu aussi un grand nombre d’améliorations internes du compilateur et de son écosystème : le système de construction du compilateur est en train de subir un sévère ménage de printemps, tandis que les tests d’intégration continue ont été améliorés, notamment pour mieux supporter les anciennes versions de Windows. Parallèlement, un travail de fond est en cours pour améliorer le déverminage de programme OCaml et préparer le changement de modèle de mémoire nécessaire pour une future version multicœur d’OCaml. Ces évolutions n’apportent pas encore de changements visibles pour la plupart des utilisateurs, mais devraient porter leurs fruits dans les versions à venir. Un changement plus visible, même s’il ne concerne essentiellement que des utilisateurs experts, est l’intégration progressive d’une architecture de greffons (_plugins_) dans le compilateur. Pour l’instant, ces greffons peuvent, par exemple, transformer l’arbre de syntaxe abstrait comme le ferait un préprocesseur basé sur les points d’extensions, effectuer une passe de vérification supplémentaire sur les types inférés par le vérificateur de type du compilateur, ou encore modifier la représentation interne Lambda. # Reason ![Critique de la raison pure](http://pix.toile-libre.org/upload/original/1497039867.jpg) En dehors de l’évolution du langage lui‐même, un projet inhabituel est né récemment dans les locaux de Facebook[^1]. Ce projet se nomme [Reason](https://facebook.github.io/reason/) et a pour but de rénover la syntaxe d’OCaml. Il a été initié par un petit groupe mené par Jordan Walke (le créateur initial de la bibliothèque [React](https://facebook.github.io/react/)). ## L’objectif La raison de Reason (huhu !) est que la syntaxe d’OCaml rebute certaines personnes. Cependant, OCaml s’inscrit de plus en plus dans le milieu industriel (comme le montrent les exemples de Facebook, mais aussi Jane Street, dans une tout autre mesure). Dans un désir de _démocratisation_, l’équipe ReasonML décida de créer une nouvelle syntaxe pour OCaml du nom de Reason. Comparé à la syntaxe originale d’OCaml, Reason se rapproche de la syntaxe de JavaScript. Par exemple, les accolades et les points‐virgules font un retour en force : ```OCaml let hello name_opt = let name = match name_opt with | None -> "world" | Some x -> x in Format.printf "Hello %s!" name ``` devient : ```ocaml let hello name_opt => { let name = switch name_opt { | None => "world"; | Some n => n; }; Format.printf "Hello %s!" name } ``` D’une certaine manière `Rust` a eu la même idée en proposant une syntaxe très proche du `C++`. [Elixir](http://elixir-lang.org/) rejoint le même objectif dans une autre mesure. La syntaxe de Reason essaye également d’augmenter la cohérence interne de la syntaxe et de corriger des erreurs historiques. Par exemple, les constructeurs de types se lisent de droite à gauche comme les fonctions dans Reason : ```ocaml type constructeur_de_type 'argument = { id:int, x:'argument } ``` L’objectif est, bien entendu, plus large et a amorcé notamment un élan autour des outils qui peuvent aider le développeur à utiliser OCaml. Le _top‐level_ interactif amélioré `utop`, qui semble unanimement reconnu comme étant l’outil pour tester du code OCaml, fut réutilisé pour Reason et l’accueil auprès des nouveaux développeurs (extérieurs à la communauté OCaml) fut couronné de succès. Le service d’aide à l’édition `merlin`, qui permet d’intégrer la coloration syntaxique, mais aussi l’inférence de type dans les éditeurs, eut aussi son intégration avec Reason et tout ceci apporta une légitimité à la continuation de ces projets pour Reason mais aussi pour OCaml. Enfin, le gestionnaire de paquets `opam` reste toujours la pierre angulaire de l’écosystème d’OCaml et donc l’est aussi par définition pour Reason. Ce dernier se voit donc désormais utilisé par des gens n’ayant pas forcément en tête les subtilités de l’écosystème d’OCaml (comme `ocamlfind`). Au‐delà de cette nouvelle syntaxe, l’équipe de Reason attache donc une attention particulière à l’environnement de développement d’OCaml. Cela permet notamment d’apporter une réelle critique extérieure aux outils de développement OCaml et en particulier une critique justifiée sur la difficulté de prise en main de ces outils pour un débutant. ## Ce qu’est Reason Reason n’est ni plus ni moins qu’une option dans le compilateur. Nous parlons ici de l’option `-pp` qui permet de remplacer la partie frontale du compilateur par un préprocesseur _ad hoc_. Le préprocesseur Reason prend donc du code Reason en entrée, le transforme en arbre de syntaxe abstrait OCaml et passe cet arbre au compilateur OCaml classique. Ceci permet entre autres de garder la compatibilité avec l’existant et de profiter à la fois des logiciels et bibliothèques déjà développés en OCaml et de la nouvelle syntaxe Reason, et réciproquement. Il existe d’ailleurs un outil permettant de convertir du code OCaml vers du code Reason ! Partager la partie centrale du compilateur permet également d’utiliser les différents _back‐ends_ disponibles pour OCaml. En particulier, OCaml dispose de deux _back‐ends_ JavaScript : _js_of_ocaml_ et _bucklescript_. Le premier, _js_of_ocaml_, est plus ancré dans l’écosystème OCaml, tandis que le second, _bucklescript_, est plus tourné vers l’écosystème JavaScript et dispose d’une intégration avec _npm_, un gestionnaire de paquets JavaScript. Grâce à ces _back‐ends_, l’équipe ReasonML a pu convertir environ 25 % du code de FaceBook Messenger en code Reason. ## Un avenir imprévisible On peut cependant s’interroger sur l’interaction de la communauté OCaml existante et de cette nouvelle communauté Reason, bien plus centrée sur le Web, l’écosphère JavaScript et _npm_. Les atomes crochus n’abondent pas forcément entre ces deux communautés. Le bon point reste tout de même l’ouverture de l’écosystème d’OCaml à des développeurs qui ne faisaient pas de l’OCaml. Cela permet notamment d’apporter des perspectives neuves et de revitaliser des problématiques de développement parfois oubliées dans l’écosystème OCaml. Le succès n’est peut‐être pas au rendez‐vous et le projet a encore besoin de faire ses preuves auprès d’un large public (problématique qu’on peut corréler avec [Hack](http://hacklang.org/) auprès de ceux qui font du PHP d’ailleurs). Mais le retour ne semble être que bénéfique au final pour l’ensemble des communautés ! [^1]: elle a été extérieure puisqu’elle a été initiée par Facebook alors que ce dernier ne faisait pas encore partie du consortium OCaml. [^1]: elle a été extérieure puisqu’elle a été initiée par Facebook alors que ce dernier ne faisait pas encore partie du consortium OCaml.

AltStyle によって変換されたページ (->オリジナル) /