Migrating from Ruby 2.7 to Ruby 3.x introduces several new features and improvements that enhance performance, usability, and functionality. This guide highlights the key features you can now utilize in Ruby 3.x that were not available or significantly improved from Ruby 2.7.

Improved Performance

Ruby 3.x includes significant performance improvements, partly due to MJIT (Method-based Just-in-Time Compilation). This can lead to faster execution times for your applications. The goal of Ruby 3 is to be three times faster than Ruby 2.0, focusing on real-world performance improvements.

Ractor (Actor-model Based Parallel Execution)

Ractor allows for parallel execution without the need for thread-safe code, enabling concurrency without threading issues.

1
2
3
4
ractor = Ractor.new do
  "Hello from Ractor"
end
ractor.take # => "Hello from Ractor"

Fiber Scheduler

Enhancements to Fibers and the introduction of a new scheduler interface allow for lightweight concurrency, suitable for I/O-bound operations like HTTP requests and database queries.

1
2
3
4
5
6
require 'async'

Async do |task|
  task.sleep 1
  puts "Hello, async world!"
end

Rightward Assignment

Rightward assignment is a new syntax feature that can be useful in pattern matching and conditional assignments.

1
2
42 => x
puts x # => 42

Pattern Matching Improvements

Ruby 3.x enhances the pattern matching introduced in Ruby 2.7 with more flexible and powerful options.

1
2
3
4
5
6
case [0, 1, 2]
in [a, 1, b]
  puts "Matched with a=#{a} and b=#{b}"
else
  puts "No match"
end

New Syntax for Keyword Arguments

Ruby 3.x introduces a clear distinction between positional and keyword arguments, eliminating the ambiguity present in Ruby 2.7.

1
2
3
4
def foo(a, b: 0)
  a + b
end
foo(1, b: 2) # => 3

Hash#except

The Hash#except method allows for easier manipulation of hashes by excluding specified keys.

1
2
hash = { a: 1, b: 2, c: 3 }
hash.except(:b) # => { a: 1, c: 3 }

Enhanced Enumerator::Lazy

Enhancements to Enumerator::Lazy improve performance and usability for handling large data sets lazily.

1
lazy_enum = (1..Float::INFINITY).lazy.select { |x| x % 3 == 0 }.first(10)

One-line Pattern Matching

You can now use pattern matching directly in assignment, making code more concise.

1
2
3
{a: 1, b: 2} => {a:, b:}
puts a # => 1
puts b # => 2

Find Pattern in Enumerable

New methods like Enumerable#tally provide more tools for working with collections.

1
['a', 'b', 'a'].tally # => {"a"=>2, "b"=>1}

New String Methods

Ruby 3.x adds methods like String#delete_prefix and String#delete_suffix for better string manipulation.

1
2
"HelloWorld".delete_prefix("Hello") # => "World"
"HelloWorld".delete_suffix("World") # => "Hello"

Safe Navigation Operator with Assignment

The safe navigation operator (&.) now works with assignments.

1
2
3
hash = { foo: { bar: nil } }
hash[:foo]&.[](:bar) = "baz"
puts hash[:foo][:bar] # => "baz"

Beginless Ranges

Beginless ranges allow for more flexible range operations.

1
2
arr = [1, 2, 3, 4, 5]
arr[..3] # => [1, 2, 3, 4]

New Built-in Methods

Array#intersection helps find common elements in arrays.

1
[1, 2, 3] & [2, 3, 4] # => [2, 3]

Improved Error Messages

Ruby 3.x provides more informative and readable error messages, making debugging easier.

By leveraging these new features and improvements, you can write more efficient, readable, and maintainable code in Ruby 3.x. Happy coding!


[alex_rocha] by alex

🇧🇷Senior Software Developer