La version 4.0.0 du langage de programmation Ruby est sortie, introduisant « Ruby Box », une nouvelle fonctionnalité qui permet de séparer les définitions, et « ZJIT », un nouveau compilateur JIT
La version 4.0.0 de Ruby est sortie et introduit « Ruby Box » et « ZJIT ». Ruby Box est une nouvelle fonctionnalité (expérimentale) qui permet de séparer les définitions. ZJIT est un nouveau compilateur juste-à-temps (JIT), développé comme la prochaine génération de YJIT. Ractor, le mécanisme d'exécution parallèle de Ruby, a bénéficié de plusieurs améliorations. En termes de performances, de nombreuses structures de données internes ont été améliorées afin de réduire considérablement les conflits sur un verrou global, ce qui permet un meilleur parallélisme.
Ruby est un langage de programmation polyvalent. Il a été conçu dans un souci de productivité et de simplicité. En Ruby, tout est un objet, y compris les types de données primitifs. Il a été développé au milieu des années 1990 par Yukihiro « Matz » Matsumoto au Japon. Ruby est un langage interprété, de haut niveau et à typage dynamique ; son interpréteur utilise le ramasse-miettes et la compilation juste à temps (JIT). Il prend en charge plusieurs paradigmes de programmation, notamment la programmation procédurale, orientée objet et fonctionnelle. Selon son créateur, Ruby a été influencé par Perl, Smalltalk, Eiffel, Ada, BASIC et Lisp.
La version 4.0.0 de Ruby est sortie et introduit « Ruby Box » et « ZJIT ». Ruby Box est une nouvelle fonctionnalité (expérimentale) qui permet de séparer les définitions. ZJIT est un nouveau compilateur juste-à-temps (JIT), développé comme la prochaine génération de YJIT. ZJIT est plus rapide que l'interpréteur, mais pas encore aussi rapide que YJIT. Cette version apporte également des mises à jour des classes principales.
Ractor, le mécanisme d'exécution parallèle de Ruby, a bénéficié de plusieurs améliorations. En termes de performances, de nombreuses structures de données internes ont été améliorées afin de réduire considérablement les conflits sur un verrou global, ce qui permet un meilleur parallélisme. Les Ractors partagent désormais moins de données internes, ce qui réduit les conflits de cache CPU lors de l'exécution en parallèle.
Ruby Box
Ruby Box est une nouvelle fonctionnalité (expérimentale) qui permet de séparer les définitions. Ruby Box est activée lorsque la variable d'environnement RUBY_BOX=1 est spécifiée. La classe est Ruby::Box.
Les définitions chargées dans une boîte sont isolées dans celle-ci. Ruby Box peut isoler/séparer les monkey patches, les modifications des variables globales/de classe, les définitions de classe/module et les bibliothèques natives/ruby chargées des autres boîtes.
Les cas d'utilisation prévus sont les suivants :
- Exécuter des cas de test dans une boîte pour protéger les autres tests lorsque le cas de test utilise des monkey patches pour remplacer quelque chose
- Exécuter des boîtes d'applications web en parallèle pour effectuer un déploiement bleu-vert sur un serveur d'applications dans un processus Ruby
- Exécuter des boîtes d'applications web en parallèle pour évaluer les mises à jour de dépendances pendant une certaine période en vérifiant les différences de réponse à l'aide du code Ruby.
- Utiliser comme API de base (bas niveau) pour implémenter une sorte d'API « package » (haut niveau) (elle n'est pas encore conçue).
ZJIT
ZJIT est un nouveau compilateur juste-à-temps (JIT), développé comme la prochaine génération de YJIT. Vous avez besoin de Rust 1.85.0 ou d'une version plus récente pour compiler Ruby avec le support ZJIT, et ZJIT est activé lorsque --zjit est spécifié.
L'équipe développe un nouveau compilateur pour Ruby afin d'augmenter les performances maximales (taille d'unité de compilation plus importante et SSA IR) et d'encourager davantage de contributions externes (en devenant un compilateur plus traditionnel).
ZJIT est plus rapide que l'interpréteur, mais pas encore aussi rapide que YJIT. Les développeurs sont encouragés à tester ZJIT, mais il n'est pas recommandé de ne pas le déployer en production pour le moment.
Améliorations de Ractor
Ractor, le mécanisme d'exécution parallèle de Ruby, a bénéficié de plusieurs améliorations. Une nouvelle classe, Ractor::Port, a été introduite pour résoudre les problèmes liés à l'envoi et à la réception de messages. De plus, Ractor.shareable_proc facilite le partage d'objets Proc entre les Ractors.
En termes de performances, de nombreuses structures de données internes ont été améliorées afin de réduire considérablement les conflits sur un verrou global, ce qui permet un meilleur parallélisme. Les Ractors partagent désormais moins de données internes, ce qui réduit les conflits de cache CPU lors de l'exécution en parallèle.
Ractor a été introduit pour la première fois dans Ruby 3.0 en tant que fonctionnalité expérimentale, l'objectif est de supprimer son statut « expérimental » l'année prochaine.
Modifications du langage
- *nil n'appelle plus nil.to_a, de la même manière que **nil n'appelle pas nil.to_hash.
- Les opérateurs binaires logiques (||, &&, and et or) au début d'une ligne continuent la ligne précédente, comme le point fluide. Les exemples de code suivants sont équivalents :
Code Ruby : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 if condition1 && condition2 ... end
Auparavant :
Code Ruby : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 if condition1 && condition2 ... end
Code Ruby : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 if condition1 && condition2 ... end
Mises à jour des classes principales
Array
- Array#rfind a été ajouté comme alternative plus efficace à array.reverse_each.find.
- Array#find a été ajouté comme remplacement plus efficace de Enumerable#find.
Binding
- Binding#local_variables n'inclut plus de paramètres numérotés. De plus, Binding#local_variable_get, Binding#local_variable_set et Binding#local_variable_defined? refusent de traiter les paramètres numérotés.
- Binding#implicit_parameters, Binding#implicit_parameter_get et Binding#implicit_parameter_defined? ont été ajoutés pour accéder aux paramètres numérotés et au paramètre « it ».
Enumerator
- Enumerator.produce accepte désormais un argument clé facultatif size pour spécifier la taille de l'énumérateur. Il peut s'agir d'un entier, de Float::INFINITY, d'un objet appelable (tel qu'un lambda) ou de nil pour indiquer une taille inconnue. Si elle n'est pas spécifiée, la taille par défaut est Float::INFINITY.
Code Ruby : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11 # Infinite enumerator enum = Enumerator.produce(1, size: Float::INFINITY, &:succ) enum.size # => Float::INFINITY # Finite enumerator with known/computable size abs_dir = File.expand_path("./baz") # => "/foo/bar/baz" traverser = Enumerator.produce(abs_dir, size: -> { abs_dir.count("/") + 1 }) { raise StopIteration if it == "/" File.dirname(it) } traverser.size # => 4
ErrorHighlight
Lorsqu'une erreur ArgumentError est levée, elle affiche désormais des extraits de code pour l'appel de méthode (appelant) et la définition de méthode (appelé).
Code Ruby : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9 test.rb:1:in 'Object#add': wrong number of arguments (given 1, expected 2) (ArgumentError) caller: test.rb:3 | add(1) ^^^ callee: test.rb:1 | def add(x, y) = x + y ^^^ from test.rb:3:in '<main>'
Fiber
Introduction de la prise en charge de l'argument Fiber#raise(cause:) similaire à Kernel#raise.
Fiber::Scheduler
- Introduction de Fiber::Scheduler#fiber_interrupt pour interrompre une fibre avec une exception donnée. Le cas d'utilisation initial consiste à interrompre une fibre qui attend une opération d'E/S bloquante lorsque l'opération d'E/S est fermée.
- Introduction de Fiber::Scheduler#yield pour permettre au planificateur de fibres de continuer le traitement lorsque les exceptions de signal sont désactivées.
- Réintroduction du hook Fiber::Scheduler#io_close pour IO#close asynchrone.
- Appel de Fiber::Scheduler#io_write lors du vidage du tampon d'écriture IO.
File
- File::Stat#birthtime est désormais disponible sous Linux via l'appel système statx lorsqu'il est pris en charge par le noyau et le système de fichiers.
IO
- IO.select accepte Float::INFINITY comme argument de délai d'expiration.
- Un comportement obsolète, la création de processus par les méthodes de classe IO avec un | en tête, a été supprimé.
Kernel
- Kernel#inspect vérifie désormais l'existence d'une méthode #instance_variables_to_inspect, ce qui permet de contrôler les variables d'instance affichées dans la chaîne #inspect :
Code Ruby : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12 class DatabaseConfig def initialize(host, user, password) @host = host @user = user @password = password end private def instance_variables_to_inspect = [:@host, :@user] end conf = DatabaseConfig.new("localhost", "root", "hunter2") conf.inspect #=> #<DatabaseConfig:0x0000000104def350 @host="localhost", @user="root">
- Un comportement obsolète, la création de processus par Kernel#open avec un | en tête, a été supprimé.
Math
Math.log1p et Math.expm1 ont été ajoutés.
Pathname
Pathname est passé du statut de gem par défaut à celui de classe centrale de Ruby.
Proc
- Proc#parameters affiche désormais les paramètres optionnels anonymes sous la forme [:opt] au lieu de [:opt, nil], ce qui rend la sortie cohérente avec le cas où le paramètre anonyme est obligatoire.
Ractor
- La classe Ractor::Port a été ajoutée pour un nouveau mécanisme de synchronisation permettant la communication entre les Ractors.
Code Ruby : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10 port1 = Ractor::Port.new port2 = Ractor::Port.new Ractor.new port1, port2 do |port1, port2| port1 << 1 port2 << 11 port1 << 2 port2 << 12 end 2.times{ p port1.receive } #=> 1, 2 2.times{ p port2.receive } #=> 11, 12
- Ractor::Port fournit les méthodes suivantes :
Ractor::Port#receive.
Ractor::Port#send (ou Ractor::Port#<<)
Ractor::Port#close.
Ractor::Port#closed?.
En conséquence, Ractor.yield et Ractor#take ont été supprimés.
- Ractor#join et Ractor#value ont été ajoutées pour attendre la fin d'un Ractor. Elles sont similaires à Thread#join et Thread#value.
- Ractor#monitor et Ractor#unmonitor ont été ajoutées en tant qu'interfaces de bas niveau utilisées en interne pour implémenter Ractor#join.
- Ractor.select n'accepte désormais que les Ractors et les Ports. Si des Ractors sont fournis, elle renvoie une valeur lorsqu'un Ractor se termine.
- Ractor#default_port a été ajouté. Chaque Ractor dispose d'un port par défaut, qui est utilisé par Ractor.send et Ractor.receive.
- Ractor#close_incoming et Ractor#close_outgoing ont été supprimés.
- Ractor.shareable_proc et Ractor.shareable_lambda ont été introduits pour rendre Proc ou lambda partageables.
Range
- Range#to_set effectue désormais des vérifications de taille afin d'éviter les problèmes liés aux plages infinies.
- Range#overlap? gère désormais correctement les plages infinies (illimitées).
- Le comportement de Range#max sur les plages d'entiers sans début a été corrigé.
Ruby
Un nouveau module de niveau supérieur Ruby a été défini, qui contient des constantes liées à Ruby. Ce module était réservé dans Ruby 3.4 et est désormais officiellement défini.
Ruby::Box
Une nouvelle fonctionnalité (expérimentale) permettant de séparer les définitions.
Set
- Set est désormais une classe centrale, au lieu d'une classe stdlib chargée automatiquement.
- Set#inspect utilise désormais un affichage plus simple, similaire aux tableaux littéraux. (Par exemple, Set[1, 2, 3] au lieu de #<Set: {1, 2, 3}>).
- Le passage d'arguments à Set#to_set et Enumerable#to_set est désormais obsolète.
Socket
- Socket.tcp & TCPSocket.new acceptent un argument clé open_timeout pour spécifier le délai d'expiration de la connexion initiale.
- Lorsqu'un délai d'expiration spécifié par l'utilisateur se produisait dans TCPSocket.new, Errno::ETIMEDOUT ou IO::TimeoutError pouvaient auparavant être levés selon la situation. Ce comportement a été unifié afin que IO::TimeoutError soit désormais systématiquement levé. (Veuillez noter que, dans Socket.tcp, il existe encore des cas où Errno::ETIMEDOUT peut être levé dans des situations similaires, et que dans les deux cas, Errno::ETIMEDOUT peut être levé lorsque le délai d'expiration se produit au niveau du système d'exploitation.)
String
- Mise à jour d'Unicode vers la version 17.0.0 et d'Emoji vers la version 17.0. (s'applique également à Regexp)
- String#strip, strip!, lstrip, lstrip!, rstrip et rstrip! sont étendus pour accepter les arguments *selectors.
Thread
Introduction de la prise en charge de l'argument Thread#raise(cause:) similaire à Kernel#raise.
Améliorations de la mise en œuvre
- Class#new (ex. Object.new) est plus rapide dans tous les cas, mais surtout lors du passage d'arguments clés. Cela a également été intégré dans YJIT et ZJIT.
- Les tas GC de pools de tailles différentes grandissent désormais indépendamment, ce qui réduit l'utilisation de la mémoire lorsque seuls certains pools contiennent des objets à longue durée de vie
- Le balayage GC est plus rapide sur les pages d'objets volumineux.
- Les objets « ivar génériques » (String, Array, TypedData, etc.) utilisent désormais un nouvel objet interne « fields » pour un accès plus rapide aux variables d'instance.
- Le GC évite de maintenir une table id2ref interne jusqu'à sa première utilisation, ce qui accélère l'allocation object_id et le balayage GC.
- object_id et hash sont plus rapides sur les objets Class et Module.
- Les entiers bignum plus grands peuvent rester intégrés à l'aide d'une allocation à largeur variable.
- Random, Enumerator::Product, Enumerator::Chain, Addrinfo, StringScanner et certains objets internes sont désormais protégés par une barrière d'écriture, ce qui réduit la surcharge du GC.
Source : Annonce de Ruby 4.0.0
Et vous ?
Pensez-vous que ces améliorations sont crédibles ou pertinentes ?
Quel est votre avis sur cette version ?
Voir aussi :
La version 3.4.0 de Ruby est désormais disponible, ajoutant la référence au paramètre de bloc "it", le support de Happy Eyeballs v2 à la bibliothèque socket et rendant Prism comme parseur par défaut
Brut RB, un nouveau framework Web simple mais complet pour Ruby, sans contrôleurs, verbes ou ressources. Vous construisez simplement des pages, des formulaires et des gestionnaires d'action unique







Pensez-vous que ces améliorations sont crédibles ou pertinentes ?
Répondre avec citation
Partager