Skip to content

Ruby 3.1 support #7015

@headius

Description

@headius

See https://github.com/ruby/ruby/blob/v3_1_0/NEWS.md for the full 3.1 NEWS file.

This listing includes all features from the Ruby 3.1 news file that might be relevant to JRuby. I have removed sections specific to the Ruby C API or the static analysis and type-profiling libraries that are not currently supported on JRuby.

See also #6878 for Ruby 3.0 features and #6464 for Ruby 2.7, which will also be included.

Language changes

  • The block argument can now be anonymous if the block will
    only be passed to another method. [Feature #11256] (Support anonymous block passthrough (3.1) #7044)

    def foo(&)
      bar(&)
    end
  • Pin operator now takes an expression. [Feature #17411]

    Prime.each_cons(2).lazy.find_all{_1 in [n, ^(n + 2)]}.take(3).to_a
    #=> [[3, 5], [5, 7], [11, 13]]
  • Pin operator now supports instance, class, and global variables.
    [Feature #17724]

    @n = 5
    Prime.each_cons(2).lazy.find{_1 in [n, ^@n]}
    #=> [3, 5]
  • One-line pattern matching is no longer experimental.

  • Parentheses can be omitted in one-line pattern matching.
    [Feature #16182]

    [0, 1] => _, x
    {y: 2} => y:
    x #=> 1
    y #=> 2
  • Multiple assignment evaluation order consistency #7440 Multiple assignment evaluation order has been made consistent with single assignment evaluation order. With single assignment, Ruby uses a left-to-right evaluation order. With this code:

    foo[0] = bar

    The following evaluation order is used:

    1. foo
    2. bar
    3. []= called on the result of foo

    In Ruby before 3.1.0, multiple assignment did not follow this
    evaluation order. With this code:

    foo[0], bar.baz = a, b

    Versions of Ruby before 3.1.0 would evaluate in the following
    order

    1. a
    2. b
    3. foo
    4. []= called on the result of foo
    5. bar
    6. baz= called on the result of bar

    Starting in Ruby 3.1.0, the evaluation order is now consistent with
    single assignment, with the left-hand side being evaluated before
    the right-hand side:

    1. foo
    2. bar
    3. a
    4. b
    5. []= called on the result of foo
    6. baz= called on the result of bar

    [Bug #4443]

  • Values in Hash literals and keyword arguments can be omitted.
    [Feature #14579]

    For example,

    • {x:, y:} is a syntax sugar of {x: x, y: y}.
    • foo(x:, y:) is a syntax sugar of foo(x: x, y: y).

    Constant names, local variable names, and method names are allowed as
    key names. Note that a reserved word is considered as a local
    variable or method name even if it's a pseudo variable name such as
    self.

  • Non main-Ractors can get instance variables (ivars) of classes/modules
    if ivars refer to shareable objects.
    [Feature #17592]

  • A command syntax is allowed in endless method definitions, i.e.,
    you can now write def foo = puts "Hello".
    Note that private def foo = puts "Hello" does not parse.
    [Feature #17398]

Command line options

  • --disable-gems is now explicitly declared as "just for debugging".
    Never use it in any real-world codebase.
    [Feature #17684]

Core classes updates

Note: We're only listing outstanding class updates.

  • Array

  • Class

    • Class#subclasses, which returns an array of classes
      directly inheriting from the receiver, not
      including singleton classes.
      [Feature #18273]

      class A; end
      class B < A; end
      class C < B; end
      class D < A; end
      A.subclasses    #=> [D, B]
      B.subclasses    #=> [C]
      C.subclasses    #=> []
  • Enumerable

    • Enumerable#compact is added. [Feature #17312]

    • Enumerable#tally now accepts an optional hash to count. [Feature #17744]

    • Enumerable#each_cons and each_slice to return a receiver. [GH-1509]

      [1, 2, 3].each_cons(2){}
      # 3.0 => nil
      # 3.1 => [1, 2, 3]
      
      [1, 2, 3].each_slice(2){}
      # 3.0 => nil
      # 3.1 => [1, 2, 3]
  • Enumerator::Lazy

  • File

    • File.dirname now accepts an optional argument for the level to
      strip path components. [Feature #12194]
  • GC

    • "GC.measure_total_time = true" enables the measurement of GC.
      Measurement can introduce overhead. It is enabled by default.
      GC.measure_total_time returns the current setting.
      GC.stat[:time] or GC.stat(:time) returns measured time
      in milli-seconds. [[Feature #10917]]

    • GC.total_time returns measured time in nano-seconds. [[Feature #10917]]

  • Integer

  • Kernel

  • Marshal

    • Marshal.load now accepts a freeze: true option.
      All returned objects are frozen except for Class and
      Module instances. Strings are deduplicated. [Feature #18148]
  • MatchData

  • Method / UnboundMethod

    • Method#public?, Method#private?, Method#protected?,
      UnboundMethod#public?, UnboundMethod#private?,
      UnboundMethod#protected? have been added. [Feature #11689]
  • Module

  • Process

    • Process._fork is added. This is a core method for fork(2).
      Do not call this method directly; it is called by existing
      fork methods: Kernel.#fork, Process.fork, and IO.popen("-").
      Application monitoring libraries can overwrite this method to
      hook fork events. [Feature #17795]
  • Struct

    • Passing only keyword arguments to Struct#initialize is warned.
      You need to use a Hash literal to set a Hash to a first member.
      [Feature #16806]

    • StructClass#keyword_init? is added [Feature #18008]

  • String

    • Update Unicode version to 13.0.0 [Feature #17750]
      and Emoji version to 13.0 [Feature #18029]

    • String#unpack and String#unpack1 now accept an offset: keyword
      argument to start the unpacking after an arbitrary number of bytes
      have been skipped. If offset is outside of the string bounds
      ArgumentError is raised. [Feature #18254]

  • Thread

  • Thread::Backtrace

    • Thread::Backtrace.limit, which returns the value to limit backtrace
      length set by --backtrace-limit command line option, is added.
      [Feature #17479]
  • Thread::Queue

    • Thread::Queue.new now accepts an Enumerable of initial values.
      [Feature #17327]
  • Time

    • Time.new now accepts optional in: keyword argument for the
      timezone, as well as Time.at and Time.now, so that is now
      you can omit minor arguments to Time.new. [Feature #17485]

      Time.new(2021, 12, 25, in: "+07:00")
      #=> 2021-12-25 00:00:00 +0700

      At the same time, time component strings are converted to
      integers more strictly now.

      Time.new(2021, 12, 25, "+07:30")
      #=> invalid value for Integer(): "+07:30" (ArgumentError)

      Ruby 3.0 or earlier returned probably unexpected result
      2021-12-25 07:00:00, not 2021-12-25 07:30:00 nor
      2021-12-25 00:00:00 +07:30.

    • Time#strftime supports RFC 3339 UTC for unknown offset local
      time, -0000, as %-z. [Feature #17544]

  • TracePoint

    • TracePoint.allow_reentry is added to allow reenter while TracePoint
      callback.
      [Feature #15912]
  • $LOAD_PATH

  • Fiber Scheduler

    • Add support for Addrinfo.getaddrinfo using address_resolve hook.
      [Feature #17370]

    • Introduce non-blocking Timeout.timeout using timeout_after hook.
      [Feature #17470]

    • Introduce new scheduler hooks io_read and io_write along with a
      low level IO::Buffer for zero-copy read/write. [Feature #18020]

    • IO hooks io_wait, io_read, io_write, receive the original IO object
      where possible. [Bug #18003]

    • Make Monitor fiber-safe. [Bug #17827]

    • Replace copy coroutine with pthread implementation. [Feature #18015]

  • Refinement

    • New class which represents a module created by Module#refine.
      include and prepend are deprecated, and import_methods is added
      instead. [Bug #17429]

Stdlib updates

Stdlib compatibility issues

  • ERB#initialize warns safe_level and later arguments even without -w.
    [Feature #14256]

  • lib/debug.rb is replaced with debug.gem

  • Kernel#pp in lib/pp.rb uses the width of IO#winsize by default.
    This means that the output width is automatically changed depending on
    your terminal size. [Feature #12913]

  • Psych 4.0 changes Psych.load as safe_load by the default.
    You may need to use Psych 3.3.2 for migrating to this behavior.
    [Bug #17866]

Implementation improvements

These do not apply directly to JRuby, but we should check if we have equivalent optimizations in place.

  • Inline cache mechanism is introduced for reading class variables.
    [Feature #17763]

  • instance_eval and instance_exec now only allocate a singleton class when
    required, avoiding extra objects and improving performance. [GH-5146]

  • The performance of Struct accessors is improved. [GH-5131]

  • mandatory_only? builtin special form to improve performance on
    builtin methods. [GH-5112]

  • Experimental feature Variable Width Allocation in the garbage collector.
    This feature is turned off by default and can be enabled by compiling Ruby
    with flag USE_RVARGC=1 set. [Feature #18045] [Feature #18239]

Debugger

  • A new debugger debug.gem is bundled.
    debug.gem is a fast debugger implementation, and it provides many features
    like remote debugging, colorful REPL, IDE (VSCode) integration, and more.
    It replaces lib/debug.rb standard library.

  • rdbg command is also installed into bin/ directory to start and control
    debugging execution.

error_highlight

  • A built-in gem called error_highlight has been introduced.
    It shows fine-grained error locations in the backtrace.

Miscellaneous changes

  • lib/objspace/trace.rb is added, which is a tool for tracing the object
    allocation. Just by requiring this file, tracing is started immediately.
    Just by Kernel#p, you can investigate where an object was created.
    Note that just requiring this file brings a large performance overhead.
    This is only for debugging purposes. Do not use this in production.
    [Feature #17762]

  • Now exceptions raised in finalizers will be printed to STDERR, unless
    $VERBOSE is nil. [Feature #17798]

  • ruby -run -e httpd displays URLs to access. [Feature #17847]

  • Add ruby -run -e colorize to colorize Ruby code using
    IRB::Color.colorize_code.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions