Ruby 3.4.0 Released: What’s New, Improved, and Breaking

Ruby 3.4.0 Released: What’s New, Improved, and Breaking

Ruby 3.4.0 was released on December 25, 2024, bringing exciting new features, performance improvements, and some breaking changes. Here’s a practical guide of what’s new and what you should know before upgrading to this version.

Highlights

  • New it block parameter reference: Cleaner, more readable blocks using it instead of the original _1.
  • Language and core changes: Easier keyword argument handling, string literal warnings, reserved names, and updates to core classes.
  • Standard library updates: RubyGems, Bundler, JSON, Tempfile, and more get useful updates.
  • Compatibility and miscellaneous changes: New error message formats, hash and float handling, block and performance warnings, and deprecated features removed.
  • Prism is now the default parser: Ruby’s parser is now Prism, making it possible for better tooling and error messages.
  • Socket library upgrade: Happy Eyeballs v2 means faster, more reliable network connections out of the box.
  • YJIT and Modular GC: Advanced performance and memory improvements for those using Ruby’s JIT or experimenting with garbage collection.

New Features

it Block Parameter Reference

Ruby 3.4 introduces the it block parameter, making one liner blocks more readable when you only need a single argument. For example:

numbers = [10, 15, 20, 25]
doubled = numbers.map { it * 2 }
# => [20, 30, 40, 50]

words = %w[cat elephant dog]
long_words = words.select { it.length > 3 }
# => ["elephant"]

users = [User.new("Ana"), User.new("Bob")]
names = users.map { it.name }
# => ["Ana", "Bob"]

squares = [1, 2, 3].map { it * it }
# => [1, 4, 9]

Remember that previously, you had to use numbered parameters like _1:

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

With it, your intent is clearer and your code is easier to read, especially when you use simple blocks.

Inspiration from Other Languages

The idea of a default block parameter like it isn’t from Ruby. Languages such as Kotlin and Groovy use it as the implicit name for a single lambda or closure parameter:

  • Kotlin: list.filter { it > 0 }
  • Groovy: list.each { println it }

Other languages use similar concepts but with some differences:

  • Scala: Uses _ as a placeholder for parameters: list.map(_ * 2)
  • Clojure: Uses % for anonymous function parameters: (map #(* % 2) [1 2 3])

Language and Core Changes

  • String literals: Mutating string literals without a frozen_string_literal comment now triggers a deprecation warning. This change is part of Ruby’s ongoing effort to make frozen string literals the default in future versions. For more details, see Ruby 3.4: New Defaults and What They Mean for Your Code opens a new window .
    str = "hello"
    str << " world" # triggers warning unless frozen_string_literal is set
    
  • Keyword splatting: You can now use **nil to pass no keyword arguments. This fixes a long standing previous bug, **nil would raise an error, but now it correctly passes an empty keyword hash, making code more reliable and predictable.

    def foo(**kwargs)
      kwargs
    end
    foo(**nil) # => {}
    
  • Block passing/indexing: Passing blocks or keyword arguments in index operations is no longer allowed. For example:
    arr = [1, 2, 3]
    # Previously allowed, now raises an error:
    arr[0, &:to_s] # ArgumentError in Ruby 3.4
    
    hash = {a: 1}
    # Passing keywords in index:
    hash[:a, foo: :bar] # ArgumentError in Ruby 3.4
    
  • Reserved toplevel name: ::Ruby is now reserved.

Core Class Updates

  • Exception: set_backtrace accepts new formats.
  • GC: New configuration options.
  • Ractor: More features for Ruby’s concurrency model.
  • Range: Range#size raises an error for non-iterable ranges.
    (1..Float::INFINITY).size # raises TypeError
    

Standard Library Updates

  • RubyGems: New --attestation for gem push boosts signature security and fixes default gem tagging. Details. opens a new window
  • Bundler: bundle lock --add-checksums adds lockfile checksums; JRuby warnings with bundler/setup and -w are fixed.
  • JSON: Parsing is about 1.5x faster!
    require 'json'
    JSON.parse('{"a":1}') # now faster
    
  • Tempfile: New anonymous: true option for easier cleanup.
    Tempfile.create(anonymous: true) # file is removed immediately
    
  • win32/sspi.rb: Extracted to a separate gem.

Several bundled gems have been included by default.


Compatibility Issues

  • Error messages and backtraces: Formatting has changed for clarity.
  • Hash#inspect: Now uses modern symbol key syntax and spaces around =>.
    {user: 1}.inspect # => "{user: 1}"
    {"user" => 1}.inspect # => '{"user" => 1}'
    
  • Float/String#to_f: Now accepts decimal strings with omitted decimal parts.
    "1.".to_f    # => 1.0
    "1.E-1".to_f # => 0.1
    
  • Refinement#refined_class: Removed.

  • Standard library: Deprecated constants and methods removed in Net::HTTP, Timeout, URI, and DidYouMean.

Miscellaneous Changes

  • Block warnings: Passing a block to a method that does not use it now triggers a warning in verbose mode.
  • Performance warnings: Redefining core methods triggers a warning.

Other Features

Prism: The New Default Parser

Ruby 3.4 switches its default parser from the legacy parse.y to the new Prism parser. The main motivation for this change is to modernize Ruby’s parsing system, making it easier to maintain and extend. Prism is written in modern C++ and designed for better performance, improved error messages, and easier integration with tools like editors and language servers.

By adopting Prism, the Ruby core team aims to:

  • Simplify future language changes and syntax improvements
  • Provide more accurate and helpful error reporting
  • Enable better tooling for developers (e.g., syntax highlighting, code analysis)
  • Reduce technical debt from the older parser codebase

For most users, this change is invisible, but it prepare for a more robust and flexible Ruby ecosystem.

Socket Library: Happy Eyeballs v2

Ruby’s socket library is used for network communication—connecting to servers, sending and receiving data, and building networked applications. If you’ve ever used TCPSocket, Socket.tcp, or similar classes, you’ve used the socket library.

In Ruby 3.4, the socket library now features Happy Eyeballs Version 2 (RFC 8305), a modern algorithm for faster and more reliable network connections. This means Ruby will try both IPv6 and IPv4 in parallel, reducing connection delays and improving connectivity.

For most developers, this improvement is automatic and requires no configuration, but it’s a big win for anyone building networked Ruby apps.

Example: Faster TCP Connections

require 'socket'

# Connect to a server using TCPSocket
socket = TCPSocket.new('example.com', 80)
socket.puts "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n"
puts socket.read
socket.close

With Happy Eyeballs v2, Ruby will quickly try both IPv6 and IPv4 addresses, reducing connection delays if one protocol is slow or unavailable. This means your networked Ruby applications will connect faster and more reliably, especially in environments with mixed IPv6/IPv4 support.

YJIT: Performance and Features

YJIT, Ruby’s JIT compiler, gets several upgrades:

  • Unified memory limit (--yjit-mem-size)
  • Compilation logs (--yjit-log)
  • More Ruby methods optimized for speed
  • Lower memory usage and better stats

Modular Garbage Collector

Ruby’s garbage collector is now customizable. You can swap in alternative GC implementations, including an experimental one based on MMTk (requires Rust). This is mostly for advanced users and future experimentation.


Should You Upgrade?

Ruby 3.4.0 is a solid release with performance improvements, new features, and some breaking changes. Review the compatibility details and test your code before upgrading, especially if you rely on deprecated features or custom C extensions.

Has your team been struggling with an upgrade? We can help opens a new window .

Want to know what’s next for Ruby? Check out the official Ruby roadmap opens a new window .


References


Get the book