According to Ruby tradition, the core team will release Ruby 3.4 on December 25—but the preview has been out since May! If you're anticipating the release like we are, you're probably wondering what's new in Ruby 3.4. There aren't any huge changes in this release, but you'll want to be aware of a few really cool things.

New in Ruby 3.4 announcement

Let's dig into some of the language changes first.

Language changes

Language changes are the most immediately relevant changes to most Ruby developers. Let's take a quick look at each of them!

Frozen string literals

If you've written Ruby for even a little while, you've probably seen a file that starts with:

# frozen_string_literal: true

The example above is a magic comment, and it actually has meaning to the Ruby interpreter! This comment tells the interpreter to treat each string in this file as if it had freeze called on it. If you try to modify a String in a file with this magic comment, you'll get a runtime error.

In Ruby 3.4, strings will act as if they're frozen by default. An attempt to mutate them will result in a deprecation warning instead of an error. A future version of Ruby will enforce the default frozen string literals by raising an exception if you try to mutate them. This transitionary period will give Ruby developers time to migrate their apps.

Default block parameter

Ruby 3.4 introduces a default block parameter to make short code blocks cleaner.

Before Ruby 2.7, printing each element of an array with the each method looked something like:

[1, 2, 3].each { |item| puts item }

Ruby 2.7 introduced numbered parameters to remove the need to name them. After Ruby 2.7, you could write the same code as:

[1, 2, 3].each { puts _1 }

Ruby 2.7's improvement is more straightforward but not exactly clear. If you're unfamiliar with this Ruby syntax, you may struggle to understand what's happening here. Ruby 3.4 is introducing an even better way to do this same thing:

[1, 2, 3].each { puts it }

Keyword splatting nil

In Ruby versions before 3.4, using the double splat operator (**) with nil raised a TypeError. This sort of made sense because nil could not be implicitly converted into a hash.

Ruby 3.4 provides a simple change to this - it implicitly converts nil into a hash. Calling ** on nil will be like calling ** on an empty hash.

Core classes updates

The core class updates aren't as immediately relevant to Ruby developers as the language changes, but they're definitely worth understanding!

Exception#set_backtrace

A feature request on the Ruby issue tracker described setting the backtrace with an array of strings before this change in Ruby 3.4 as "lossy." The exception previously returned nil on #backtrace_locations.

In Ruby 3.4, Exception#set_backtrace will accept a Thread::Backtrace::Location array so that you can rebuild a Backtrace instance and have a fully functioning Exception.

Range#size

Range#size also has new behavior in Ruby 3.4. If the range that size is being called on is not iterable, Ruby will now throw a TypeError. This is a small change to behavior that you'll only notice if you're calling size on a small subset of ranges.

Other changes new in Ruby 3.4

Another small change in Ruby 3.4 is to methods that get passed to a block they don't use. When running in verbose mode, Ruby will now throw a warning if you pass a block to a method that doesn't use the block.

You may also be happy to hear that Ruby 3.4 improves the performance of Array.each due to an implementation rewrite!

Lastly, another update is to how error messages and backtraces are displayed. Ruby will now use single quotes instead of backticks when relevant and display a class name before a method name.

Upgrading to Ruby 3.4

Upgrading to Ruby 3.4 shouldn't be a major lift for most folks. The most labor-intensive part will be removing all those unneeded frozen string magic comments! Taking the time to upgrade to take advantage of all that's new in Ruby 3.4 will pay dividends, so don't delay!

And don't forget—to get more Ruby news and even tutorials like this one in your inbox, sign up for the Honeybadger newsletter!

author photo
Jeffery Morhous

Jeff is a Software Engineer working in healthcare technology using Ruby on Rails, React, and plenty more tools. He loves making things that make life more interesting and learning as much he can on the way. In his spare time, he loves to play guitar, hike, and tinker with cars.

More articles by Jeffery Morhous