IronRuby 4.0.5:.NET 10と.NET 11で動くRuby 4.0
9月末に、prismをパーサーに使ってIronRubyをRuby 4.0に対応させた私のフォーク、IronRuby 4.0について書きました。当時は.NET 8で動き、最初のダウンロードは4.0.0-preview1という名前でした。それから6週間で6つのリリースを重ね、IronRuby 4.0.5が出ました。.NET 10と.NET 11 で動く最初のリリースで、.NET 8を使わない最初のリリースでもあります。
$ ./ironruby -e 'puts RUBY_DESCRIPTION'
IronRuby 4.0.5 (4.0.0) on .NET 10.0.15 [x86_64-linux]
.NET 8をやめた理由
Microsoftによる.NET 8のサポートは、昨日2026年11月10日に終了しました。4.0.4が.NET 8向けの最後のリリースです。4.0.5からIronRubyは net10.0 と net11.0 向けにビルドされ、.NET 8のためだけに必要だったコードは削除されました。
ダウンロードはそれぞれ2種類になりました。
- .NET 10 が標準です。ファイル名はこれまでと同じで、たとえば
ironruby-4.0.5-linux-x64.tar.gzです。Windowsインストーラーもこちらを使います。.NET 10はLTSリリースで、2028年11月14日までサポートされます。 - .NET 11 は名前に
-net11-が付き、Linux、Windows、macOS向けがあります。インストーラーはありません。
どちらも自分のランタイムを同梱しているので、Rubyスクリプトを動かすだけなら.NETをインストールする必要はありません。IronRubyを組み込むプログラムや、そのアセンブリを読み込むプログラムだけが、.NET 10以降を必要とします。
.NET 11では起動が約5%短くなり、TruffleRubyのベンチマーク集は約3.5%速く動きます。それでも標準を.NET 10にしているのは、LTSリリースだからです。
ランタイムの変更にともなって、小さな変化が2つあります。.NET 9以降の BigInteger の上限により、Integerは約2**31ビットより大きくできなくなりました。1 << 2**31 は、メモリ確保に失敗したときのCRubyと同じく NoMemoryError になります。また、Windowsの zlib は.NETに含まれるzlib-ngを使うようになりました。そのため Zlib::ZLIB_VERSION が変わり、圧縮したバイト列が4.0.4と異なることがあります。展開した結果は同じです。
9月からの変化
4.0.5そのものは小さなリリースです。大きな変更は、その前の4つのリリースにありました。私が特に大事だと思うものを紹介します。
SQLiteを使ったRails、Windowsでも
Sam Ruby(@rubys)さんが、自身のプロジェクトRoundhouseでトランスパイルしたRailsアプリを動かし、最初のバグを見つけてくれました。macOSのパイプとソケットでPumaが起動できなかったこと、大きなレスポンスが途中で切れていた IO#write_nonblock、そしてLinuxでのSQLiteのクラッシュです。3つとも4.0.1で直りました。
4.0.2では、Rails 8.1のアプリがWindows上でSQLiteを使って動きます。gem install rails、rails new、scaffold、マイグレーション、TurboとStimulus、そしてPuma上の bin/rails server までです。Windowsで人気のgemを試したところ、rubocop、rspec、pry、prawnなど81個がCRubyとバイト単位で同じ出力を返しました。TLSもnet/httpとPumaの両方で動きます。
Windowsインストーラーとirb
4.0.3から、RubyInstallerのようなWindowsインストーラーがあります。C:\IronRuby40-x64 にインストールされ、管理者権限は不要で、ironruby、iirb、igem をPATHに追加します。irb と gem はCRubyのままなので、両方を並べて使えます。
irbはWindowsでもCRubyと同じように動くようになりました。色付き表示、型に基づく補完、コンソールでの日本語などの正しい表示に対応しています。また、JRubyのインタプリタが jruby であるように、インタプリタの名前は ironruby になりました。ターミナルでスクリプトなしに起動するとirbが開きます。
Ruby 4らしい書き方で.NETを呼ぶ
.NETの呼び出しがずっと使いやすくなりました。キーワード引数は名前で.NETのパラメーターに結びつき、ブロックはデリゲート型のパラメーターに渡されます。list.Sort { |a, b| b <=> a } や Task.Run { } がそのまま動きます。
@sholdenさんのおかげで、using はC#の using ディレクティブのように.NETの名前空間も受け取れるようになりました。その拡張メソッドは、ファイルの残りの部分だけで有効です。
using System::Linq
list = System::Collections::Generic::List[Integer].new([3, 1, 2])
p list.where { it > 1 }.order_by { -it }.to_a # => [3, 2]
LINQの101のサンプルはCIで動いています。
ずっと速く
4.0.4は主に速度のためのリリースでした。ベンチマークで洗い出した、IronRubyがCRubyに大きく遅れていた箇所の多くが、解消されたか大きく縮まりました。
- rescueされる例外のコストは以前の約4分の1になりました。
- 長いStringのコピーは一定時間で終わります。100 KBの
s.dupは83 µsから0.3 µsになりました。 RationalとComplexはC#で書かれています。Rational(1, 3)は540 nsから49 nsになり、CRubyより速くなりました。- ruby-benchのlobstersは31〜38%速くなり、protoboeufのデコードは81秒から1.3秒になりました。
- Rubyで書かれたDoomのレンダラーでは、1フレームが約27 msから16〜18 msになりました。YJITなしのCRubyは22〜25 msです。
弱点は今も例外です。.NETの例外処理の仕組みのため、例外を投げるのに数十マイクロ秒かかり、CRubyの1〜6マイクロ秒に比べて遅いままです。
CRubyにより近く
IronRubyがCRuby 4.0と同じように動くようになった点を、ほかにもいくつか挙げます。
- 深い再帰は、rescueできる
SystemStackErrorになります。以前はプロセスが終了していました。 - Ruby 4.0のAPIで
Ractorが使えます。CRubyのRactorテストの153項目のうち146項目が通ります。 - エラーの表示はCRubyと同じで、error_highlightやprismの注釈付き構文エラーも出ます。
- エラーメッセージは、CRuby 3.4以降と同じく名前を
'このように'引用します。 - 拡張をC#に移植したことで、strptime、yajl-ruby、zstd-rubyなど、C拡張を持つgemがさらに動くようになりました。ruby-benchの大きなベンチマーク36個のうち34個が動きます。
ありがとう
IronRubyは、外部から初めてコントリビューションを受けました。macOSとソケットの修正をしてくれたSam Rubyさん、macOSの File#flock と ir -S を直してくれた@khasinskiさん、そしてrefinement、LINQ、スレッドなど多くを手がけてくれた@sholdenさんに感謝します。
試してみる
リリースページに、Linux x64、Windows x64、Apple silicon搭載macOS向けのダウンロードがあります。Windowsではインストーラー ironruby-4.0.5-win-x64-setup.exe がいちばん簡単です。それ以外ではアーカイブを展開します。
$ tar xzf ironruby-4.0.5-linux-x64.tar.gz
$ cd ironruby-4.0.5-linux-x64
$ ./ironruby
$ ./ironruby script.rb
$ ./igem.sh install rack
どのファイルにも署名付きのビルド来歴証明(attestation)があり、どのワークフローがどのコミットからビルドしたかを確認できます。
$ gh attestation verify ironruby-4.0.5-linux-x64.tar.gz --repo Largo/ironruby
macOS版はCIでビルドしていますが、まだほとんどテストしていません。IronRubyを試して何か動かないことがあれば、issueを作るか、メールをください。