URL: https://linuxfr.org/news/sortie-de-ruby-3-0 Title: Sortie de Ruby 3.0 Authors: contra-sh Ysabeau, Quidam, miko, palm123 et Yves Bourguignon Date: 2021-08-21T16:12:24+02:00 License: CC By-SA Tags: ruby Score: 4 Le 25 décembre 2020 le langage Ruby est passé en version 3.0 ! ![three](https://i.ibb.co/N9dYKmy/3.jpg) _Image de [Jack Hunter](https://unsplash.com/@jacktthunter)._ Cette version est le fruit de cinq ans de travail, le travail sur la branche 3.0 ayant commencé en 2015. La suite de cette dépêche retrace les changements contenus dans cette nouvelle version. ---- [Site officiel de Ruby](https://www.ruby-lang.org/en/) [Annonce officielle de la sortie de Ruby 3](https://www.ruby-lang.org/en/news/2020/12/25/ruby-3-0-0-released/) [Installer Ruby](https://www.ruby-lang.org/fr/downloads/) ---- # Versions La date du 25 décembre n’est pas un hasard puisque cela fait plusieurs années que les versions mineures sortent le 25 décembre. Petit rappel des sorties de Ruby : - Ruby 1.0 est sorti le 25 décembre 1996 - Ruby 2.0 le 24 février 2013 - Ruby 2.1 le 25 décembre 2013 - Ruby 2.2 le 25 décembre 2014 - Ruby 2.5 le 25 décembre 2015 - Ruby 2.4 le 25 décembre 2016 - Ruby 2.5 le 25 décembre 2017 - Ruby 2.6 le 25 décembre 2018 - Ruby 2.7 le 25 décembre 2019 La liste quasi complète des versions de Ruby peut se trouver [ici](https://www.ruby-lang.org/en/downloads/releases/). # Liens vers d’anciennes dépêches LinuxFR Quelques liens vers des dépêches LinuxFR autour de Ruby et son écosystème : - [Ruby 2.0 est sorti](https://linuxfr.org/news/ruby-2-0-est-sorti) (2013) - [JRuby 1.7.0](https://linuxfr.org/news/jruby-1-7-0) (2012) - [Rubinius](https://linuxfr.org/news/rubinius-10-est-sorti) (2010) # Performances Une des principales améliorations de Ruby 3.0.0 concerne les performances. En effet, Ruby peut parfois exécuter votre code jusqu’à trois fois plus vite. Ci-dessous les résultats d’un benchmark tiré de l'[annonce officielle](https://www.ruby-lang.org/en/news/2020/12/25/ruby-3-0-0-released/) : ![Résultats benchmark performances](https://i.ibb.co/C5Y4SmP/ruby3x3.png) L’accélération provient principalement de l’utilisation du [JIT](https://fr.wikipedia.org/wiki/Compilation_%C3%A0_la_vol%C3%A9e) soit « Just-In-Time » compilation. Rappel, pour celles et ceux qui ne connaissent pas ce procédé : un interpréteur produit généralement du « byte code » (sorte de code simplifié de plus haut niveau que l’assembleur mais en restant bas niveau, parfois au format binaire). Ce byte code est ensuite exécuté par une « machine virtuelle ». Dans certains cas la frontière entre interpréteur et machine virtuelle est très mince (Perl, Python avec CPython, Ruby avec CRuby < 1.9) ou plus marquée (Raku = Rakudo + MoarVM/JVM/JS, Ruby = Ruby + YARV, Erlang = Erlang + BEAM) même si cela ne change pas grand-chose d’un point de vue utilisateur (le code source semble exécuté par une seule et même entité). Le processus de génération de bytecode peut se faire parfois ligne par ligne (interpréteur de Basic) mais peut également être précédé d’une étape de génération de format intermédiaire avec des optimisations (par exemple via un arbre de syntaxe abstraite). On nomme parfois cette étape une étape de « compilation » mais il ne s’agit pas de compilation dans le même sens du terme que pour JIT. Le JIT consiste à « compiler » certaines portions de code en code natif. Ici pour Ruby on parle de MJIT pour « Method Based JIT » c’est-à-dire que les boucles « chaudes » ne seront pas candidates à la compilation mais que seules les fonctions sont concernées. Les mesures de performances sont présentées avec « [optcarrot](https://github.com/mame/optcarrot) » qui est un émulateur de console. C’est une bonne chose puisque c’est un cas d’usage réel (les calculs mathématiques répétitifs sont parfois utilisés pour les benchmarks de JIT, mais ils sont peu représentatifs car ils leur sont très favorables). D’un autre côté, les exécutions transactionnelles (typiquement des appels web à un site web en [Ruby On Rails](https://rubyonrails.org/)) seront beaucoup moins sensibles aux améliorations du JIT. Le JIT n’est pas une nouveauté de Ruby 3.0.0, il a en fait été [introduit dans Ruby 2.6](https://www.bigbinary.com/blog/mjit-support-in-ruby-2-6). Autre bonne nouvelle, en Ruby 3.0, la taille du JIT généré a fortement été réduite ! # Détails de fonctionnement du MJIT MJIT signifie que ce sont les fonctions qui sont candidates à la compilation. Il s’agit donc de remplacer des fonctions interprétées par des fonctions compilées sur la pile d’appel de fonctions. Le MJIT de Ruby a une approche d’observation. Les méthodes ne sont pas compilées de manière trop optimiste (ce qui semble avoir été un reproche à la JVM par le passé, qui se traduisait par un ralentissement au démarrage) mais les appels de méthodes sont notés et après plusieurs appels, une fonction est mise en attente « pour compilation ». Les approches pessimistes gâchent des gains possibles, les approches optimistes pénalisent le démarrage quant aux approches « spéculatives », elles nécessitent un mécanisme de « dé-optimisation ». Dans la pile d’attente on retrouve les fonctions à optimiser, attendant leur tour pour être compilées. L’exécution continue donc en parallèle et lorsque la fonction est compilée par ce processus externe, il peut remplacer la version interprétée sur la pile d’appel. La compilation se fait en utilisant un compilateur disponible sur la plateforme. Tout simplement en générant un code source en C, puis en utilisant GCC pour compiler: ![MJIT queue compilation](https://i.ibb.co/Xtk5n9C/mjitqueue.png) _Image tirée de [The method JIT compiler for Ruby 2.6](https://k0kubun.medium.com/the-method-jit-compiler-for-ruby-2-6-388ee0989c13) par [k0kubun](https://k0kubun.medium.com/)._ L’avantage de ce processus est sa simplicité et de pouvoir « s’acheter » facilement de la portabilité (JIT partout ou GCC est disponible) et également de bénéficier de l’optimisation de code des compilateurs. Mais cela pose tout de même certains problèmes : - accès en écriture nécessaire pour Ruby sur une portion du système hôte ; - nécessité de disposer des outils de développement sur la machine hôte (vous avez GCC sur vos machines de production ? Pas moi !) # Ractor Ruby 3.0.0 introduit également les [Ractor](https://docs.ruby-lang.org/en/3.0.0/doc/ractor_md.html). Il s’agit d’un modèle de concurrence basé sur les messages. Les ractors permettent de gérer plus facilement les exécutions concurrentes tout en aidant à l’isolation des données. Les ractors sont une *abstraction* de concurrence et ils se veulent thread safe (partagent moins que des threads) sans pour autant le garantir. Chaque ractor possède un ou plusieurs fils d’exécution. Les Ractor sont expérimentaux et n’acceptent pas toute la syntaxe Ruby. # Fibers/coroutines Ruby 3.0 introduit également de nouvelles méthodes pour la concurrence légère avec des nouvelles routines de contrôle. # Notre époque sera statique ou ne sera pas Depuis de nombreuses années, les langages interprétés à typage faible proposent des annotations pour donner les types de manière « statique ». ## RBS Ruby 3.0 étend sa syntaxe grâce à RBS qui est une *gem* qui apporte une grammaire de définitions. RBS permet d’ajouter la syntaxe pour des types avancés comme les unions, la surcharge de méthodes, les génériques ou le *duck typing* avec interfaces. Une définition RBS pourra ressembler à ceci : ```ruby # Classes class User attr_reader name : String attr_reader age : Integer def initialize : (name: String, age: Integer) -> [String, Integer] end ``` ## TypeProf TypeProf est un analyseur de programme qui permet de générer (déduire) les annotations (la grammaire RBS vue précédemment) à partir d’un programme Ruby. TypeProf n’est pas encore compatible avec toute la syntaxe Ruby. À terme, on pourra utiliser le source Ruby avec ses annotations pour faire tout ce qu’on fait habituellement avec de l’analyse statique de code. # Autres nouveautés de Ruby 3.0.0 L’assignement avec la flèche `=>` par exemple `42 => linuxfr`. Nouveau comportement de `in`: - `in` retourne à présent un booléen ; - pour trouver un pattern ; - `case/in` perd son statut « expérimental ». Nouvelle syntaxe : des méthodes « sans fin » (sans mot clé `end`). # Conclusion Ruby sort donc sa version majeure qui se concentre sur les performances, l’exécution concurrente et le typage statique. Souhaitons bonne route à la branche 3 de Ruby tout en rappelant que [le site](https://linuxfr.org/) sur lequel vous lisez cette dépêche est lui-même écrit en… [Ruby](https://github.com/linuxfrorg/linuxfr.org) !