Ruby 3.2 was released on Christmas day,and I’ve been playing around with its new features.The highlights this year arethe performance gains from YJIT,WebAssembly support,faster regular expressions,and a new way to define immutable value objects,
(This is only a list of thingsI found most interesting about this release.If you’re looking for a more complete list,take a look at therelease announcement.)
YJIT is now production ready (and really fast!)
YJIT, the new JIT compiler for Ruby,was released last yearas an experimental feature.Now it’s been marked production ready,and brings even more performance gains.Here are a couple of readsabout real world performance gains:
- Uf*ck Kayserilioglu has writtenabout deploying a prerelease version of Ruby 3.2 with YJITto render Shopify storefronts,and seeing 10% speedups.
- Peter Solnica has benchmarkedthe dry-rb libraries,and had some impressive numbers to share there.
YJIT was alsocompletely rewritten in Rustin order to make it easier to maintain.This allowed the teamto quickly add support for ARM.This means that you can now run YJITon your M-series macsor a Raspberry Pi.
Immutable objects with Data.define
The newly introduced Data
classallows you to defineimmutable value objects.
# Create a Point data classPoint = Data.define(:x, :y)# Instantiate a point objectp = Point.new(x: 3, y: 7)
This might seem familiarbecause we already have Struct.new
which defines similar classes.However, Data
classes are immutable,so don’t have setters for the attributes.
point.x = 42#=> undefined method `x=' for #<data Point x=3, y=7> (NoMethodError)
Data
also defines the deconstruct
and deconstruct_keys
methodsso that the objects can be pattern matched like this:
case pointin Point(0, 0) puts "Origin"in Point(x, y) if x + y > 10 puts "Too far away"in Point(x, y) puts "(#{x}, #{y})"end
Struct
with keyword args
There’s a small usability improvement with structs as well.The keyword_init: true
argument is no longer neededto initialize structs with keyword args.
# Ruby 3.1Point = Struct.new(:x, :y, keyword_init: true)# Ruby 3.2Point = Struct.new(:x, :y)Point.new(x: 2, y: 3)#=> #<struct Point x=2, y=3>
Regular expressions
There are improvements to Regex
,mainly to prevent ReDOS (regexp denial-of-service) attacks.Firstly, the regexp matching algorithm has been improvedso that many matches will complete in linear time.For regexes that can’t use this optimization,you can also set a timeoutso that a Regexp::TimeoutError
is raisedif the match exceeds that time.
# Set a 2s timeout for a single regexpattern = Regexp.new(/foo/, timeout: 2)"foo".match(pattern)# Or set a global timeoutRegexp.timeout = 5
IRB
One of my favorite things about recent releases of Rubyis the focus on tools like IRB.Ruby 3.2 bundles the latest version 1.6 of IRB.This brings support for a lot of the debugging commandsthat you might have seen in gems like pry
and byebug
.Stan Lo, who worked on many of these featureshas written in detail aboutthe new features of IRB.
As someone who has always usedpry
and pry-byebug
,I’m excited about these changes.We will be able to get most of the benefitsof those toolsout of the box with Ruby.
Better error messages
syntax_suggest
has been integrated into Ruby,and points out missing or extra end
s in your code.This functionality was previously in a gemcalled dead_end
,but it was merged into Ruby itself.
Unmatched `end', missing keyword (`do', `def`, `if`, etc.) ?> 2 def foo> 4 end> 5 endtest.rb:5: syntax error, unexpected `end' (SyntaxError)
The builtin error_highlight
gemnow highlights the relevant argumentfor TypeError
and ArgumentError
.
test.rb:3:in `+': nil can't be coerced into Integer (TypeError)bar = 1 + foo[5] ^^^^^^ from test.rb:3:in `<main>'
WebAssembly support
Ruby now supports WebAssembly,which means that Ruby can now run in browsers!You can already see this in action in the Try Ruby playground.Another example isRuby Syntax Tree,which converts Ruby code into s-expressions.(Kevin Newton has written more about ithere).
Other changes
Set
is now a builtin class,and you no longer needtorequire "set"
to use it.bundle gem
now supports--ext=rust
to allow building gems with rust extensions.(details here)
Further reading
With these posts,I try to highlight some of the changesthat I found most interesting,and often skip over features I might not use.If you’re looking for a more comprehensive look at the release,I highly recommend looking at therelease announcement,changelog,and the excellentRuby References website,which covers all the new features in detail with lots of examples.
Other links
- Year in Review 2022: Tenderlove’s Ruby and Rails Reflections and Predictions
- It is not what you expect, but it is what you want: how Data#initialize is designed
This article is part of the What's New in Ruby series. To read about a different version of Ruby, pick the version here:
2.3 2.4 2.5 2.6 2.7 3.0 3.1 3.2 3.3