Ruby 3.0.0-preview2 リリース

Ruby 3.0に向けてフィードバックを得るためのリリースである、Ruby 3.0.0-preview2が公開されました。

Ruby 3.0には、多くの新しい機能やパフォーマンスの改善が含まれます。 その一部を以下に紹介します。

静的解析

RBS

RBSはRubyプログラムの型を記述するための言語です。

TypeProfなどの型検査ツールを初めとする静的解析を行うツールは、RBSを利用することでRubyプログラムをより精度良く解析することができます。

RBSでは、Rubyプログラムのクラスやモジュールの型を定義します。メソッドやインスタンス変数、定数とその型、継承やmixinなどの関係などが記述できます。

RBSはRubyプログラムに頻出するパターンをサポートするように設計されており、ユニオン型、メソッドオーバーロード、ジェネリクスなどの機能を提供します。さらに「インタフェース型」によってダックタイピングをサポートします。

Ruby 3.0には、このRBS言語で書かれた型定義を処理するためのライブラリである rbs gemが同梱されています。

クラスやモジュール、定数を定義する、簡単なRBSの例を示します。

module ChatApp
  VERSION: String
  class Channel
    attr_reader name: String
    attr_reader messages: Array[Message]
    attr_reader users: Array[User | Bot]              # `|` は `User` か `Bot` のインスタンスを表現する「ユニオン型」です
    def initialize: (String) -> void
    def post: (String, from: User | Bot) -> Message   # メソッドオーバーロードを記述することもできます
            | (File, from: User | Bot) -> Message
  end
end

詳細については、rbs gemのREADMEを参照してください。

TypeProf

TypeProf は Ruby パッケージに同梱された型解析ツールです。

TypeProf の現在の主な用途は一種の型推論です。

型注釈の無い普通の Ruby コードを入力し、どんなメソッドが定義されどのように使われているかを解析し、型シグネチャのプロトタイプを RBS フォーマットで生成します。

次は TypeProf の簡単なデモです。

サンプル入力

# test.rb
class User
  def initialize(name:, age:)
    @name, @age = name, age
  end
  attr_reader :name, :age
end
User.new(name: "John", age: 20)

サンプル出力

$ typeprof test.rb
# Classes
class User
  attr_reader name : String
  attr_reader age : Integer
  def initialize : (name: String, age: Integer) -> [String, Integer]
end

サンプル入力を”test.rb”という名前で保存し、typeprof test.rbというコマンドで TypeProf の解析ができます。

TypeProf をオンラインで試すこともできます(サーバサイドで TypeProf を動かしているので、サーバが落ちたらごめんなさい)。

詳しくはドキュメントデモを見てください。

残念ながら TypeProf はまだ実験的で、あまり完成度は高くありません。Ruby 言語のサブセットだけがサポートされていて、型エラー検出の機能は限定的です。ですがいま急速に改良中であり、言語機能のカバレッジ増強、解析効率の向上、利便性の向上などを行っています。フィードバックを歓迎します。

Ractor (experimental)

Ractor はアクターモデル風の並行・並列制御機構であり、スレッド安全に関する懸念をなく、Rubyで並列処理を行うための機能として設計されています。

複数のRactorを作成すると、それらは並列計算機上で並列に実行されます。Ractor間では、ほとんどのオブジェクトが共有できないように設計されているため、スレッド安全なプログラムにすることができます。メッセージの送受信により、Ractor間のコミュニケーションを行うことが可能です。

Ractor間でのオブジェクトの共有を制限するために、複数Ractorでの実行時には、いくつかのRubyの機能に制限が入ります(ただし、複数のRactorを用いない場合には、これまでのRubyと何も変わりません)。

Ractorの仕様と実装は、まだ発展途上であるため、実験的機能として提供されます。初回のRactorの生成時には実験的機能であることが警告で表示されます。

次の小さなプログラムでは、二つのRactorを用いてn.prime?nは比較的大きな値)の計算を並列に実行します。動かしてみると、逐次実行にくらべて、2コア以上の計算機で計算時間が半分程度になることが確認できます。

require 'prime'
# n.prime? with sent integers in r1, r2 run in parallel
r1, r2 = *(1..2).map do
  Ractor.new do
    n = Ractor.receive
    n.prime?
  end
end
# send parameters
r1.send 2**61 - 1
r2.send 2**61 + 15
# wait for the results of expr1, expr2
p r1.take #=> true
p r2.take #=> true

より詳細は、doc/ractor.md をご覧ください。

Scheduler (experimental)

Thread#scheduler is introduced for intercepting blocking operations. This allows for light-weight concurrency without changing existing code. Watch “Don’t Wait For Me, Scalable Concurrency for Ruby 3” for an overview of how it works. Currently supported classes/methods:

  • Mutex#lock, Mutex#unlock, Mutex#sleep
  • ConditionVariable#wait
  • Queue#pop, SizedQueue#push
  • Thread#join
  • Kernel#sleep
  • IO#wait, IO#read, IO#write and related methods (e.g. #wait_readable, #gets, #puts and so on).
  • IO#select is not supported.

The current entry point for concurrency is Fiber.schedule{...} however this is subject to change by the time Ruby 3 is released.

Currently, there is a test scheduler available in Async::Scheduler. See doc/scheduler.md for more details.

その他の主要な新機能

  • 1行パターンマッチが in の代わりに => を使うようになりました。
          # version 3.0
          {a: 0, b: 1} => {a:}
          p a # => 0
          # version 2.7
          {a: 0, b: 1} in {a:}
          p a # => 0
    
  • 一行メソッド定義が書けるようになりました。
        def square(x) = x * x
    
  • findパターンが書けるようになりました。
        case ["a", 1, "b", "c", 2, "d", "e", "f", 3]
        in [*pre, String => x, String => y, *post]
          p pre  #=> ["a", 1]
          p x    #=> "b"
          p y    #=> "c"
          p post #=> [2, "d", "e", "f", 3]
        end
    
  • Hash#except が組み込みになりました。
        h = { a: 1, b: 2, c: 3 }
        p h.except(:a) #=> {:b=>2, :c=>3}
    

    パフォーマンスの改善

  • MJITに多数の改善が行われています。詳細はNEWSを参照してください。
  • IRB への長いコードの貼り付けは、Ruby 2.7.0 にバンドルされているものと比較して 53 倍の速さになります。例えば、このサンプルコードの貼り付けに要する時間は、11.7 秒から 0.22 秒になります。

その他の注目すべき 2.7 からの変更点

  • キーワード引数が通常の引数から分離されました。
    • 原則として、2.7 で警告の出ていたコードは動かなくなります。詳細は別ドキュメントを参照してください。
    • 関連して、引数のフォワーディングの記法で先頭に引数を書けるようになりました。
          def method_missing(meth, ...)
            send(:"do_#{ meth }", ...)
          end
      
  • $SAFE の機能が完全に削除され、ただのグローバル変数となりました。
  • バックトレースの順序は2.5で逆転しましたが、3.0ではこれを取りやめることになりました。例外が起きた行が先に表示され、呼び出し元が後に表示されるように戻ります。
  • いくつかの標準ライブラリがアップデートされました。
    • RubyGems 3.2.0.rc.1
    • Bundler 2.2.0.rc.1
    • IRB 1.2.6
    • Reline 0.1.5
  • 以下のライブラリは標準添付ライブラリから削除されました。3.0 以降で使いたい場合は rubygems から利用してください。
    • net-telnet
    • xmlrpc
  • 以下のライブラリが新たに bundled gems になりました。Bundler から利用する場合は Gemfile に明示的に指定してください。
    • rexml
    • rss
  • 以下のライブラリが新たに default gems になりました。rubygems.org からアップデート可能です。
    • abbrev
    • base64
    • English
    • erb
    • find
    • io-nonblock
    • io-wait
    • net-ftp
    • net-http
    • net-imap
    • net-protocol
    • nkf
    • open-uri
    • optparse
    • resolv
    • resolv-replace
    • rinda
    • securerandom
    • set
    • shellwords
    • tempfile
    • time
    • tmpdir
    • tsort
    • weakref

その他詳細については、NEWS ファイルまたはコミットログを参照してください。

なお、こうした変更により、Ruby 2.7.0 以降では 3776 個のファイルに変更が加えられ、181573 行の追加と 145096 行の削除が行われました !

ぜひ Ruby 3.0.0-preview2 を試して、フィードバックをお願いします!

ダウンロード

  • https://cache.ruby-lang.org/pub/ruby/3.0/ruby-3.0.0-preview2.tar.gz

    SIZE: 19378626
    SHA1: 25363b20225850224e7835e99906c52f2ff57792
    SHA256: 9de8661565c2b1007d91a580e9a7e02d23f1e8fc8df371feb15a2727aa05fd9a
    SHA512: 6fa4191425ae71e41894b60bd9c31d483a562ee8216886360ce18238ab48115b95be0367708612c45f634e7584fba8940a524ba0113ce0f36ce4df78a112d0b7
    
  • https://cache.ruby-lang.org/pub/ruby/3.0/ruby-3.0.0-preview2.tar.xz

    SIZE: 14244252
    SHA1: 54e4d3892ce480106382bd2d36dd7395e01b0f2a
    SHA256: 03078e82d4fb55c13837c69e56565fc49c451d11b1ca5e1b075d990d0957f181
    SHA512: 8b0e6e3ba7e5f95586b4438d965e7b09187ad599f4ac22dec3db7b176358514fe0c0890dde8912fef1ef92ffcde3f6f1228178eabadcf3a05601e5b6f05881ae
    
  • https://cache.ruby-lang.org/pub/ruby/3.0/ruby-3.0.0-preview2.zip

    SIZE: 23907144
    SHA1: 064ee265c94b3df87e737622ba84437ea0d6aeaf
    SHA256: 19e295ae50934ddac2b366f0c7c8de9bd710d596b76eba02152f3641e5ce2b23
    SHA512: 598def50ef9e8ae1f44e05ff2c4e35acf252437286f08644ba5e301ebff2db399140bafa72868877100d6ffa736a4474cb7b99ecea8bdf835ed113ab250bb3d9
    

Ruby とは

Rubyはまつもとゆきひろ (Matz) によって1993年に開発が始められ、今もオープンソースソフトウェアとして開発が続けられています。Rubyは様々なプラットフォームで動き、世界中で、特にWebアプリケーション開発のために使われています。