|
| 1 | +--- |
| 2 | +layout: news_post |
| 3 | +title: "Ruby 3.4.0 Released" |
| 4 | +author: "naruse" |
| 5 | +translator: |
| 6 | +date: 2024-12-25 00:00:00 +0000 |
| 7 | +lang: en |
| 8 | +--- |
| 9 | + |
| 10 | +{% assign release = site.data.releases | where: "version", "3.4.0" | first %} |
| 11 | +We are pleased to announce the release of Ruby {{ release.version }}. Ruby 3.4 adds `it` block parameter reference, |
| 12 | +change Prism as default parser, adds Happy Eyeballs Version 2 support to socket library, improves YJIT, |
| 13 | +adds Modular GC, and so on. |
| 14 | + |
| 15 | +## `it` is introduced |
| 16 | + |
| 17 | +`it` is added to reference a block parameter with no variable name. [[Feature #18980]] |
| 18 | + |
| 19 | +```ruby |
| 20 | +ary = ["foo", "bar", "baz"] |
| 21 | + |
| 22 | +p ary.map { it.upcase } #=> ["FOO", "BAR", "BAZ"] |
| 23 | +``` |
| 24 | + |
| 25 | +`it` very much behaves the same as `_1`. When the intention is to only use `_1` in a block, the potential for other numbered parameters such as `_2` to also appear imposes an extra cognitive load onto readers. So `it` was introduced as a handy alias. Use `it` in simple cases where `it` speaks for itself, such as in one-line blocks. |
| 26 | + |
| 27 | +## Prism is now the default parser |
| 28 | + |
| 29 | +Switch the default parser from parse.y to Prism. [[Feature #20564]] |
| 30 | + |
| 31 | +This is an internal improvement and there should be little change visible to the user. If you notice any compatibility issues, please report them to us. |
| 32 | + |
| 33 | +To use the conventional parser, use the command-line argument `--parser=parse.y`. |
| 34 | + |
| 35 | +## The socket library now features Happy Eyeballs Version 2 (RFC 8305) |
| 36 | + |
| 37 | +The socket library now features [Happy Eyeballs Version 2 (RFC 8305)](https://datatracker.ietf.org/doc/html/rfc8305), the latest standardized version of a widely adopted approach for better connectivity in many programming languages, in `TCPSocket.new` (`TCPSocket.open`) and `Socket.tcp`. |
| 38 | +This improvement enables Ruby to provide efficient and reliable network connections, adapted to modern internet environments. |
| 39 | + |
| 40 | +Until Ruby 3.3, these methods performed name resolution and connection attempts serially. With this algorithm, they now operate as follows: |
| 41 | + |
| 42 | +1. Performs IPv6 and IPv4 name resolution concurrently |
| 43 | +2. Attempt connections to the resolved IP addresses, prioritizing IPv6, with parallel attempts staggered at 250ms intervals |
| 44 | +3. Return the first successful connection while canceling any others |
| 45 | + |
| 46 | +This ensures minimized connection delays, even if a specific protocol or IP address is delayed or unavailable. |
| 47 | +This feature is enabled by default, so additional configuration is not required to use it. To disable it globally, set the environment variable `RUBY_TCP_NO_FAST_FALLBACK=1` or call `Socket.tcp_fast_fallback=false`. Or to disable it on a per-method basis, use the keyword argument `fast_fallback: false`. |
| 48 | + |
| 49 | +## YJIT |
| 50 | + |
| 51 | +### TL;DR |
| 52 | + |
| 53 | +* Better performance across most benchmarks on both x86-64 and arm64 platforms. |
| 54 | +* Reduced memory usage through compressed metadata and a unified memory limit. |
| 55 | +* Various bug fixes: YJIT is now more robust and thoroughly tested. |
| 56 | + |
| 57 | +### New features |
| 58 | + |
| 59 | +* Command-line options |
| 60 | + * `--yjit-mem-size` introduces a unified memory limit (default 128MiB) to track total YJIT memory usage, |
| 61 | + providing a more intuitive alternative to the old `--yjit-exec-mem-size` option. |
| 62 | + * `--yjit-log` enables a compilation log to track what gets compiled. |
| 63 | +* Ruby API |
| 64 | + * `RubyVM::YJIT.log` provides access to the tail of the compilation log at run-time. |
| 65 | +* YJIT stats |
| 66 | + * `RubyVM::YJIT.runtime_stats` now always provides additional statistics on |
| 67 | + invalidation, inlining, and metadata encoding. |
| 68 | + |
| 69 | +### New optimizations |
| 70 | + |
| 71 | +* Compressed context reduces memory needed to store YJIT metadata |
| 72 | +* Allocate registers for local variables and Ruby method arguments |
| 73 | +* When YJIT is enabled, use more Core primitives written in Ruby: |
| 74 | + * `Array#each`, `Array#select`, `Array#map` rewritten in Ruby for better performance [[Feature #20182]]. |
| 75 | +* Ability to inline small/trivial methods such as: |
| 76 | + * Empty methods |
| 77 | + * Methods returning a constant |
| 78 | + * Methods returning `self` |
| 79 | + * Methods directly returning an argument |
| 80 | +* Specialized codegen for many more runtime methods |
| 81 | +* Optimize `String#getbyte`, `String#setbyte` and other string methods |
| 82 | +* Optimize bitwise operations to speed up low-level bit/byte manipulation |
| 83 | +* Support shareable constants in multi-ractor mode |
| 84 | +* Various other incremental optimizations |
| 85 | + |
| 86 | +## Modular GC |
| 87 | + |
| 88 | +* Alternative garbage collector (GC) implementations can be loaded dynamically |
| 89 | + through the modular garbage collector feature. To enable this feature, |
| 90 | + configure Ruby with `--with-modular-gc` at build time. GC libraries can be |
| 91 | + loaded at runtime using the environment variable `RUBY_GC_LIBRARY`. |
| 92 | + [[Feature #20351]] |
| 93 | + |
| 94 | +* Ruby's built-in garbage collector has been split into a separate file at |
| 95 | + `gc/default/default.c` and interacts with Ruby using an API defined in |
| 96 | + `gc/gc_impl.h`. The built-in garbage collector can now also be built as a |
| 97 | + library using `make modular-gc MODULAR_GC=default` and enabled using the |
| 98 | + environment variable `RUBY_GC_LIBRARY=default`. [[Feature #20470]] |
| 99 | + |
| 100 | +* An experimental GC library is provided based on [MMTk](https://www.mmtk.io/). |
| 101 | + This GC library can be built using `make modular-gc MODULAR_GC=mmtk` and |
| 102 | + enabled using the environment variable `RUBY_GC_LIBRARY=mmtk`. This requires |
| 103 | + the Rust toolchain on the build machine. [[Feature #20860]] |
| 104 | + |
| 105 | +## Language changes |
| 106 | + |
| 107 | +* String literals in files without a `frozen_string_literal` comment now emit a deprecation warning |
| 108 | + when they are mutated. |
| 109 | + These warnings can be enabled with `-W:deprecated` or by setting `Warning[:deprecated] = true`. |
| 110 | + To disable this change, you can run Ruby with the `--disable-frozen-string-literal` |
| 111 | + command line argument. [[Feature #20205]] |
| 112 | + |
| 113 | +* Keyword splatting `nil` when calling methods is now supported. |
| 114 | + `**nil` is treated similarly to `**{}`, passing no keywords, |
| 115 | + and not calling any conversion methods. [[Bug #20064]] |
| 116 | + |
| 117 | +* Block passing is no longer allowed in index. [[Bug #19918]] |
| 118 | + |
| 119 | +* Keyword arguments are no longer allowed in index. [[Bug #20218]] |
| 120 | + |
| 121 | +* The toplevel name `::Ruby` is reserved now, and the definition will be warned when `Warning[:deprecated]`. [[Feature #20884]] |
| 122 | + |
| 123 | +## Core classes updates |
| 124 | + |
| 125 | +Note: We're only listing notable updates of Core class. |
| 126 | + |
| 127 | +* Exception |
| 128 | + |
| 129 | + * `Exception#set_backtrace` now accepts an array of `Thread::Backtrace::Location`. |
| 130 | + `Kernel#raise`, `Thread#raise` and `Fiber#raise` also accept this new format. [[Feature #13557]] |
| 131 | + |
| 132 | +* GC |
| 133 | + |
| 134 | + * `GC.config` added to allow setting configuration variables on the Garbage |
| 135 | + Collector. [[Feature #20443]] |
| 136 | + |
| 137 | + * GC configuration parameter `rgengc_allow_full_mark` introduced. When `false` |
| 138 | + GC will only mark young objects. Default is `true`. [[Feature #20443]] |
| 139 | + |
| 140 | +* Ractor |
| 141 | + |
| 142 | + * `require` in Ractor is allowed. The requiring process will be run on |
| 143 | + the main Ractor. |
| 144 | + `Ractor._require(feature)` is added to run requiring process on the |
| 145 | + main Ractor. |
| 146 | + [[Feature #20627]] |
| 147 | + |
| 148 | + * `Ractor.main?` is added. [[Feature #20627]] |
| 149 | + |
| 150 | + * `Ractor.[]` and `Ractor.[]=` are added to access the ractor local storage |
| 151 | + of the current Ractor. [[Feature #20715]] |
| 152 | + |
| 153 | + * `Ractor.store_if_absent(key){ init }` is added to initialize ractor local |
| 154 | + variables in thread-safty. [[Feature #20875]] |
| 155 | + |
| 156 | +* Range |
| 157 | + |
| 158 | + * `Range#size` now raises `TypeError` if the range is not iterable. [[Misc #18984]] |
| 159 | + |
| 160 | + |
| 161 | +## Standard Library updates |
| 162 | + |
| 163 | +Note: We're only listing notable updates of Standard librarires. |
| 164 | + |
| 165 | +* RubyGems |
| 166 | + * Add `--attestation` option to gem push. It enabled to store signature to [sigstore.dev] |
| 167 | + |
| 168 | +* Bundler |
| 169 | + * Add a `lockfile_checksums` configuration to include checksums in fresh lockfiles |
| 170 | + * Add bundle lock `--add-checksums` to add checksums to an existing lockfile |
| 171 | + |
| 172 | +* JSON |
| 173 | + |
| 174 | + * Performance improvements of `JSON.parse` about 1.5 times faster than json-2.7.x. |
| 175 | + |
| 176 | +* Tempfile |
| 177 | + |
| 178 | + * The keyword argument `anonymous: true` is implemented for Tempfile.create. |
| 179 | + `Tempfile.create(anonymous: true)` removes the created temporary file immediately. |
| 180 | + So applications don't need to remove the file. |
| 181 | + [[Feature #20497]] |
| 182 | + |
| 183 | +* win32/sspi.rb |
| 184 | + |
| 185 | + * This library is now extracted from the Ruby repository to [ruby/net-http-sspi]. |
| 186 | + [[Feature #20775]] |
| 187 | + |
| 188 | +## Compatibility issues |
| 189 | + |
| 190 | +Note: Excluding feature bug fixes. |
| 191 | + |
| 192 | +* Error messages and backtrace displays have been changed. |
| 193 | + * Use a single quote instead of a backtick as a opening quote. [[Feature #16495]] |
| 194 | + * Display a class name before a method name (only when the class has a permanent name). [[Feature #19117]] |
| 195 | + * `Kernel#caller`, `Thread::Backtrace::Location`'s methods, etc. are also changed accordingly. |
| 196 | + |
| 197 | + ``` |
| 198 | + Old: |
| 199 | + test.rb:1:in `foo': undefined method `time' for an instance of Integer |
| 200 | + from test.rb:2:in `<main>' |
| 201 | +
|
| 202 | + New: |
| 203 | + test.rb:1:in 'Object#foo': undefined method 'time' for an instance of Integer |
| 204 | + from test.rb:2:in '<main>' |
| 205 | + ``` |
| 206 | + |
| 207 | +* Hash#inspect rendering have been changed. [[Bug #20433]] |
| 208 | + |
| 209 | + * Symbol keys are displayed using the modern symbol key syntax: `"{user: 1}"` |
| 210 | + * Other keys now have spaces around `=>`: `'{"user" => 1}'`, while previously they didn't: `'{"user"=>1}'` |
| 211 | + |
| 212 | +* Kernel#Float() now accepts a decimal string with decimal part omitted. [[Feature #20705]] |
| 213 | + |
| 214 | + ```rb |
| 215 | + Float("1.") #=> 1.0 (previously, an ArgumentError was raised) |
| 216 | + Float("1.E-1") #=> 0.1 (previously, an ArgumentError was raised) |
| 217 | + ``` |
| 218 | + |
| 219 | +* String#to_f now accepts a decimal string with decimal part omitted. Note that the result changes when an exponent is specified. [[Feature #20705]] |
| 220 | + |
| 221 | + ```rb |
| 222 | + "1.".to_f #=> 1.0 |
| 223 | + "1.E-1".to_f #=> 0.1 (previously, 1.0 was returned) |
| 224 | + ``` |
| 225 | + |
| 226 | +* Refinement#refined_class has been removed. [[Feature #19714]] |
| 227 | + |
| 228 | +## Standard library compatibility issues |
| 229 | + |
| 230 | +* DidYouMean |
| 231 | + |
| 232 | + * `DidYouMean::SPELL_CHECKERS[]=` and `DidYouMean::SPELL_CHECKERS.merge!` are removed. |
| 233 | + |
| 234 | +* Net::HTTP |
| 235 | + |
| 236 | + * Removed the following deprecated constants: |
| 237 | + * `Net::HTTP::ProxyMod` |
| 238 | + * `Net::NetPrivate::HTTPRequest` |
| 239 | + * `Net::HTTPInformationCode` |
| 240 | + * `Net::HTTPSuccessCode` |
| 241 | + * `Net::HTTPRedirectionCode` |
| 242 | + * `Net::HTTPRetriableCode` |
| 243 | + * `Net::HTTPClientErrorCode` |
| 244 | + * `Net::HTTPFatalErrorCode` |
| 245 | + * `Net::HTTPServerErrorCode` |
| 246 | + * `Net::HTTPResponseReceiver` |
| 247 | + * `Net::HTTPResponceReceiver` |
| 248 | + |
| 249 | + These constants were deprecated from 2012. |
| 250 | + |
| 251 | +* Timeout |
| 252 | + |
| 253 | + * Reject negative values for Timeout.timeout. [[Bug #20795]] |
| 254 | + |
| 255 | +* URI |
| 256 | + |
| 257 | + * Switched default parser to RFC 3986 compliant from RFC 2396 compliant. |
| 258 | + [[Bug #19266]] |
| 259 | + |
| 260 | +## C API updates |
| 261 | + |
| 262 | +* `rb_newobj` and `rb_newobj_of` (and corresponding macros `RB_NEWOBJ`, `RB_NEWOBJ_OF`, `NEWOBJ`, `NEWOBJ_OF`) have been removed. [[Feature #20265]] |
| 263 | +* Removed deprecated function `rb_gc_force_recycle`. [[Feature #18290]] |
| 264 | + |
| 265 | +## Miscellaneous changes |
| 266 | + |
| 267 | +* Passing a block to a method which doesn't use the passed block will show |
| 268 | + a warning on verbose mode (`-w`). |
| 269 | + [[Feature #15554]] |
| 270 | + |
| 271 | +* Redefining some core methods that are specially optimized by the interpeter |
| 272 | + and JIT like `String.freeze` or `Integer#+` now emits a performance class |
| 273 | + warning (`-W:performance` or `Warning[:performance] = true`). |
| 274 | + [[Feature #20429]] |
| 275 | + |
| 276 | +See [NEWS](https://github.com/ruby/ruby/blob/{{ release.tag }}/NEWS.md) |
| 277 | +or [commit logs](https://github.com/ruby/ruby/compare/v3_3_0...{{ release.tag }}) |
| 278 | +for more details. |
| 279 | + |
| 280 | +With those changes, [{{ release.stats.files_changed }} files changed, {{ release.stats.insertions }} insertions(+), {{ release.stats.deletions }} deletions(-)](https://github.com/ruby/ruby/compare/v3_3_0...{{ release.tag }}#file_bucket) |
| 281 | +since Ruby 3.3.0! |
| 282 | + |
| 283 | +Merry Christmas, Happy Holidays, and enjoy programming with Ruby 3.4! |
| 284 | + |
| 285 | +## Download |
| 286 | + |
| 287 | +* <{{ release.url.gz }}> |
| 288 | + |
| 289 | + SIZE: {{ release.size.gz }} |
| 290 | + SHA1: {{ release.sha1.gz }} |
| 291 | + SHA256: {{ release.sha256.gz }} |
| 292 | + SHA512: {{ release.sha512.gz }} |
| 293 | + |
| 294 | +* <{{ release.url.xz }}> |
| 295 | + |
| 296 | + SIZE: {{ release.size.xz }} |
| 297 | + SHA1: {{ release.sha1.xz }} |
| 298 | + SHA256: {{ release.sha256.xz }} |
| 299 | + SHA512: {{ release.sha512.xz }} |
| 300 | + |
| 301 | +* <{{ release.url.zip }}> |
| 302 | + |
| 303 | + SIZE: {{ release.size.zip }} |
| 304 | + SHA1: {{ release.sha1.zip }} |
| 305 | + SHA256: {{ release.sha256.zip }} |
| 306 | + SHA512: {{ release.sha512.zip }} |
| 307 | + |
| 308 | +## What is Ruby |
| 309 | + |
| 310 | +Ruby was first developed by Matz (Yukihiro Matsumoto) in 1993, |
| 311 | +and is now developed as Open Source. It runs on multiple platforms |
| 312 | +and is used all over the world especially for web development. |
| 313 | + |
| 314 | +[Feature #13557]: https://bugs.ruby-lang.org/issues/13557 |
| 315 | +[Feature #15554]: https://bugs.ruby-lang.org/issues/15554 |
| 316 | +[Feature #16495]: https://bugs.ruby-lang.org/issues/16495 |
| 317 | +[Feature #18290]: https://bugs.ruby-lang.org/issues/18290 |
| 318 | +[Feature #18980]: https://bugs.ruby-lang.org/issues/18980 |
| 319 | +[Misc #18984]: https://bugs.ruby-lang.org/issues/18984 |
| 320 | +[Feature #19117]: https://bugs.ruby-lang.org/issues/19117 |
| 321 | +[Bug #19266]: https://bugs.ruby-lang.org/issues/19266 |
| 322 | +[Feature #19714]: https://bugs.ruby-lang.org/issues/19714 |
| 323 | +[Bug #19918]: https://bugs.ruby-lang.org/issues/19918 |
| 324 | +[Bug #20064]: https://bugs.ruby-lang.org/issues/20064 |
| 325 | +[Feature #20182]: https://bugs.ruby-lang.org/issues/20182 |
| 326 | +[Feature #20205]: https://bugs.ruby-lang.org/issues/20205 |
| 327 | +[Bug #20218]: https://bugs.ruby-lang.org/issues/20218 |
| 328 | +[Feature #20265]: https://bugs.ruby-lang.org/issues/20265 |
| 329 | +[Feature #20351]: https://bugs.ruby-lang.org/issues/20351 |
| 330 | +[Feature #20429]: https://bugs.ruby-lang.org/issues/20429 |
| 331 | +[Feature #20443]: https://bugs.ruby-lang.org/issues/20443 |
| 332 | +[Feature #20470]: https://bugs.ruby-lang.org/issues/20470 |
| 333 | +[Feature #20497]: https://bugs.ruby-lang.org/issues/20497 |
| 334 | +[Feature #20564]: https://bugs.ruby-lang.org/issues/20564 |
| 335 | +[Bug #20620]: https://bugs.ruby-lang.org/issues/20620 |
| 336 | +[Feature #20627]: https://bugs.ruby-lang.org/issues/20627 |
| 337 | +[Feature #20705]: https://bugs.ruby-lang.org/issues/20705 |
| 338 | +[Feature #20715]: https://bugs.ruby-lang.org/issues/20715 |
| 339 | +[Feature #20775]: https://bugs.ruby-lang.org/issues/20775 |
| 340 | +[Bug #20795]: https://bugs.ruby-lang.org/issues/20795 |
| 341 | +[Feature #20860]: https://bugs.ruby-lang.org/issues/20860 |
| 342 | +[Feature #20875]: https://bugs.ruby-lang.org/issues/20875 |
| 343 | +[Feature #20884]: https://bugs.ruby-lang.org/issues/20884 |
| 344 | +[sigstore.dev]: sigstore.dev |
| 345 | +[ruby/net-http-sspi]: https://github.com/ruby/net-http-sspi |
0 commit comments