Hackers News

Ruby 3.4 highlights

Alright, you know the drill. The Ruby team do the hard work of putting together a new version packed with features and I pick my favourites and write about them.

If you’d like to read the full set of changes, they’re over on the Ruby project website. There’s plenty more good stuff in there—these were just the changes that stood out to me.

Default block parameter name

In many situations where we pass a block in Ruby, that block receives a single argument (each, map, filter, etc). A lot of the time, we end up giving that argument a fairly generic name like item because we know that we’re working through items in a list.

[
  "beige chinos",
  "blue jorts",
  "rainbow jorts",
].filter { |item| item =~ /jorts/ }
# => ["blue jorts", "rainbow jorts"]

In Ruby 3.4, it has been added as a default name for the first parameter passed to a block. Rather than specifying a name in trivial cases like the one above, you can now write:

[
  "beige chinos",
  "blue jorts",
  "rainbow jorts",
].filter { it =~ /jorts/ }
# => ["blue jorts", "rainbow jorts"]

Better connection handling: “Happy Eyeballs Version 2”

I’ll be honest: the reason this made my list this year is that seeing it in the changelog pointed me to an interesting RFC that I hadn’t heard of before! I spent a couple of hours down a rabbit hole reading RFCs and a few snippets of source code and I thought it was worth talking about.

Ruby 3.4 adds an implementation of RFC8305 (Happy Eyeballs Version 2: Better Connectivity Using Concurrency) to its TCP socket implementation.

In a nutshell, the RFC is an attempt at describing a way for clients to handle multiple IP addresses being returned by DNS queries, particularly in the context of a dual-stack (IPv4 and IPV6) network. It describes how to make the DNS requests, how to order the addresses returned by them, and how to kick off concurrent connection attempts to those addresses in a way that balances giving the user a response quickly with not creating pointless load on servers.

RFC8305 builds on the earlier RFC6555. RFC6555 talked in relatively high-level terms about what’s needed in an algorithm that uses a hostname to establish a connection in a dual-stack environment and made reference to an approach shared by Mozilla Firefox and Google Chrome at the time. RFC8305 goes beyond that and provides much more concrete descriptions of what should be done at each stage.

One thing I really like about their approach is that they provide sensible default values for each of the tunable parameters of their algorithm, which were reached through empirical measurement of connection timings across a wide range of devices. A company with the reach of Apple, where this RFC originated, is well-placed to take measurements at the scale needed to find widely applicable defaults. It’s great to see the effort put into making the output of their work useful beyond the walls of their company.

I’m less bullish about the IPv6 transition than some of my friends. If that transition is going to be successful, it involves an unavoidable period of running dual-stack networks. When doing so caused trouble on my home network, I switched IPv6 off rather than trying to debug it. If we want people to embrace dual-stack networks—and ultimately IPv6—we need socket libraries that do the right thing by default.

Clearer exception backtraces

Okay, we’re done with the rabbit hole and we’ve got a simple one to round things off.

In Ruby 3.4, exception backtraces include the method owner (class or module) as well as the name of the method that an exception was raised from.

Let’s look at some code that raises an exception:

module Foo
  class Bar
    def inspect
      1 + '1'
    end
  end
end

p Foo::Bar.new

In Ruby 3.3 and earlier, this would print a backtrace like:

/tmp/foo.rb:4:in `+': String can't be coerced into Integer (TypeError)
	from /tmp/foo.rb:4:in `inspect'
	from /tmp/foo.rb:9:in `p'
	from /tmp/foo.rb:9:in `
'

Ruby 3.4 prints out the name of the module/class that contains each of the methods in the stack track, like:

/tmp/foo.rb:4:in `Integer#+': String can't be coerced into Integer (TypeError)
	from /tmp/foo.rb:4:in `Foo::Bar#inspect'
	from /tmp/foo.rb:9:in `Kernel#p'
	from /tmp/foo.rb:9:in `
'

It’s a small change, but I’m a big believer in anything that makes it quicker to understand what a piece of code is doing. I’m glad to see that the Ruby team still values developer experience so highly. It’s one of the best parts of writing the language.

That’s all from me. If you enjoyed this post, do get in touch with your own favourite feature from Ruby 3.4 and the best cheese you’ve eaten this Christmas.

You can find me on Mastodon or Bluesky. ✌🏻💖🎄

admin

The realistic wildlife fine art paintings and prints of Jacquie Vaux begin with a deep appreciation of wildlife and the environment. Jacquie Vaux grew up in the Pacific Northwest, soon developed an appreciation for nature by observing the native wildlife of the area. Encouraged by her grandmother, she began painting the creatures she loves and has continued for the past four decades. Now a resident of Ft. Collins, CO she is an avid hiker, but always carries her camera, and is ready to capture a nature or wildlife image, to use as a reference for her fine art paintings.

Related Articles

Leave a Reply