1 ポイント 投稿者 GN⁺ 2026-04-25 | 1件のコメント | WhatsAppで共有
  • Rubyソースをプログラム全体の型推論の後にCコードへ変換し、スタンドアロンのネイティブバイナリを生成するAOTコンパイラ
  • Rubyの生みの親であるmatzが自ら開発し、コンパイラバックエンド自体もRubyで書かれた自分自身をコンパイルするセルフホスティング構成
  • miniruby(Ruby 4.1.0dev)比で約11.6倍高速、Conway's Game of Lifeは86.7倍、ackermannは74.8倍、mandelbrotは58.1倍の高速化
  • コンパイルパイプラインはPrismベースのパーサでRubyをASTテキストに変換した後、self-hostingバックエンドが型推論とCコード生成を行い、標準Cコンパイラでスタンドアロンバイナリを作成
  • クラス、継承、ブロック、例外処理、Fiber、組み込みNFA Regexpエンジン、自動昇格Bigint、パターンマッチングなど、幅広いRuby機能をサポート
  • 8個以下のスカラーフィールドを持つ小さなクラスは値型として自動的にスタック割り当てされ、GCオーバーヘッドを完全に除去(100万件の割り当てが85ms → 2ms)
  • 文字列チェイニング a + b + c + d単一のmallocで平坦化し、ループ内のsplitはsp_StrArrayを再利用して不要な割り当てを削除
  • ループ不変の長さのホイスティング、定数伝播、3文以下のメソッド自動インライン化、反復推論の早期終了(ブートストラップ時間を約14%短縮)など、多数のコンパイル時最適化
  • 生成されたバイナリはランタイム依存ゼロで、libc + libmだけで実行可能
  • eval、メタプログラミング、ThreadおよびMutexなどは未サポート(Fiberのみサポート)
  • MITライセンス

1件のコメント

 
GN⁺ 2026-04-25
Hacker Newsのコメント
  • Matzが作ったものなら、Ruby semanticsの限界もよく分かっているはずなので信頼できる
    私の修士論文も AOT JS compiler だったが、動きはしたものの入力データの制約が大きく、結局やめた
    当時のJS開発者は自発的に制約をきちんと守ることにあまり慣れておらず、JSON.parseのように本質的に分からない入力が障害になった
    今ならTypeScriptのおかげで、当時よりずっと現実的かもしれない
    一般的な lambda calculus を見ても型推論の限界は明らかで、Matt Might周辺の論文やShed-skin Pythonの取り組みでも似たような制約が見えてくる
    eval, send, method_missing, define_method が実際のRubyコードでどれほど一般的なのか気になるし、型なしのパース、たとえばJSON入力を普通どう扱うのかも気になる

    • この設計はかなり pragmatic に見える
      Rubyのパースは変換そのものより難しいくらいなので Prism を使い、結果としてCを生成する
      基本的なRuby semantics自体の実装は、そこまで難しくない
      一方で私は純Ruby製の古い self-hosting AOT compiler を抱えていて、独自パーサーにこだわったせいでわざわざずっと険しい道を進んでしまった
      初期の80%はざっくり作ってもかなりの量のRubyコードが動くことを早い段階で学んだが、本当に難しい「2つ目の80%」は、Matzが今回のプロジェクトやmrubyで外した部分、たとえばエンコーディングやありとあらゆる周辺機能に集中している
      正直、Rubyには実際のコードで一度も見たことのない機能もかなりあるので、いくつかはdeprecatedになっても不思議ではないと思う
      send, method_missing, define_method はとてもよく使われる
      制約はmrubyに近く、その制約下でも使い道はある
      send, method_missing, define_method のサポートは比較的容易だ
      反対に eval() のサポートはとてつもなくつらい
      ただしRubyにおける eval() のかなりの割合は、静的に instance_evalのblock版 に還元できるので、その場合はAOTコンパイルがかなりやりやすくなる
      たとえば eval() に入る文字列を静的に把握できる、あるいは分解できるなら、解決の余地は大きい
      実際には多くの eval() 利用は不要だったり、単純なintrospection回避に近かったりするので、静的検査で処理できる
      私のコンパイラでも、そこがボトルネックになったらまずそこから手を付けるつもりだ
    • こうした機能がかなり多くないと Rails流のmagic は作れない
      型なしのJSON ingestionも、おそらくそうした仕組みを使っている可能性が高い
      それを取り除けば、Crystalほど強い型付けではないが、公式Rubyほどメタプログラミングに依存もしない、小さくて読みやすい言語が残る
      なので潜在力はかなり大きそうだが、結局は時間が経たないと判断できない
    • Rubyを Objective-C にコンパイルする方式なら、Rubyの機能をすべてサポートしつつ、インタプリタRubyより高速にできそうだ
    • 私は eval をよく使う側だ
      使わずに済ませることもできるが、私にとってはそのほうがより ergonomic だ
    • 私の経験で興味深いのは、eval, exec, define_method、そして Class.new, Struct.new で新しいクラスを作るパターンだ
      これらの利用の大半はアプリの boot時点 やファイルのrequire中に集中していて、ある意味ではすでにコンパイル段階に近い
  • これは RubyKaigi 2026 でMatzがたった今発表したものだ
    実験的ではあるが、Claudeの助けを借りて約1か月で作られ、ライブデモも成功した
    名前はMatzの新しい猫に由来し、その猫の名前はCard Captor Sakuraの猫の名前から来ていて、そこからさらにRubyという名前のキャラクターと対になる

    • AIがプログラムを最初から最後まで全部作るという話はよくあるが、より現実的なシナリオは 10x programmer100x programmer にすることだと思う
      Matzのような人にとっては、100xを500xまで押し上げることになるのかもしれない
    • 私の頭の中で最新のSpinelはSteven Universeのほうなので、Spinel/Ruby (Moon) pun はまったく分からなかったが、知ってから一日が楽しくなった
    • 私は当然 鉱物のspinel の話だと思っていた :)
      https://en.wikipedia.org/wiki/Spinel
    • ありがとう
      動画はまだライブではないようで、こちらのチャンネルに1本ずつ上がっているようだ
      https://www.youtube.com/@rubykaigi4884/videos
    • その猫の名前の由来の話は、Ruby Central drama やSpinel.coop創業者たちとの関係を考えると、かなり意味深に見える
      プロジェクト名も感情的に付けられたように感じる
  • 間違いなく非常に印象的だが、AI agent なしでは保守不可能に見える
    spinel_codegen.rb は2万1千行あり、あるメソッドはネストが15段階に達している
    もともとコンパイラのコードはきれいになりにくいが、それを差し引いてもこれは人間が管理するにはかなり厳しそうだ

    • コンパイラのコードは、時間さえあれば十分 きれいに できる
      コンパイラはサブシステムの境界が明確で、段階ごとのhandoffもはっきりしているので、むしろ最もmodularに作りやすい部類だ
      問題はたいてい、まず動かすことを優先してリファクタリングする時間がなく、その結果として汚さが膨らみ続けることにある
    • spinel_codegen.rb はほとんど eldritch horror レベルだ
      Claudeを使うと私もいつもこういうスパゲティコードになってしまうので、自分が何か間違っているのかと思っていた
      でも、最高レベルのプログラマだと思っている人が作った本当に面白いプロジェクトでも、コード品質がところどころかなり悪いのを見て、自分だけではなかったのだと分かった
      たとえば infer_comparison_type() は最悪の例というほどではなく、読みにくくもないが、もっと単純で明快な実装があるのにClaudeはそこへ行けない
      Set に比較演算子をまとめて include? で処理すれば、もっと短く、速く、読みやすく、保守もしやすい
      なのにClaudeはいつも if-returnの連鎖 に流れ、if-elseすら苦手な感じがある
      私のClaudeコードベースもそういうパターンだらけだが、もう自分だけではないと分かった
      一方で他のファイルはかなり良く、とくに lib ディレクトリはメインのRubyリポジトリの ext ディレクトリに対応しているようで、品質も悪くない
      APIもMRI Rubyの影響を明確に受けており、実装はかなり違っていても、Matzが元のAPIに似せるよう誘導したことで出力がより整っているように見える
      [1] https://github.com/matz/spinel/blob/98d1179670e4d6486bbd1547...
    • 今の段階では、人が手で保守できるかどうかはそこまで重要ではないと思う
      テストとベンチマークさえ通れば、ひとまず満足だ
      ただ、巨大なファイルがAIにとっても扱いやすいのかは疑問だ
      私はファイルを300行以内に抑えるようにしていて、人が理解しやすいコードは coding agents にとっても扱いやすいはずだと思っている
  • 制約はこうらしい
    No eval: eval, instance_eval, class_eval
    No metaprogramming: send, method_missing, define_method(動的)
    No threads: Thread, Mutex(Fiberはサポート)
    No encoding: UTF-8/ASCII前提
    No general lambda calculus: [] 呼び出しを伴う深いネストの -> x { }
    UTF-8/ASCII前提は個人的には大きな制約ではないが、残りはかなり多くのプログラムで実際に制約になりそうだ
    そして、これを再び入れるにはかなりの作業が必要に見える

    • これだとRubyの magic のかなりの部分が消える
  • Rubyを長く使ってきて、列挙された機能を全部使ったことのある立場からすると、むしろ進化の果てに自分が欲しくなったのは、こういう シンプルなRuby
    よりシンプルで理解しやすいのに、Ruby特有の美意識は残っている
    今はLLMのおかげでコード生成の生産性があまりに高く、昔のように開発者の生産性のためにメタプログラミングでboilerplateを減らす必要が薄れてきている
    開発者が自分でコードを書く比重そのものが下がっているからだ

    • 求めているのが単に Ruby aesthetic なら、Crystalもかなり合うかもしれない
      文法は似ていて静的型システムがあり、より効率的なコンパイル済みコードにつながる
    • eval がないのはむしろ良いと思うが、threadsとmutexes までないのは惜しい
      define_method がないのは用途を考えれば理解できる
      ただ sendmethod_missing は既存ライブラリでよく使われるし、実装もメモリ上のlookup tableをコンパイル時に構築するような形で、そこまで難しくなさそうに思える
      なので意図的に外したのか、まだそこまで到達していないのか分からない
      願わくは後者だが、少なくとも当面は互換性の面で実務投入は難しそうだ
    • メタプログラミングの利点は、もともと コードを書く量を減らすこと ではなかった
      読むべきコードを減らすこと だった
  • これは本当にすばらしく、私は長いこと Ruby向けAOT compiler を待っていた
    ただ eval やメタプログラミングのfallbackがないのは残念で、それでも小さく高性能なsubsetに集中するためにそうしたのだろう
    このAOTコンパイラで作ったgemがMRIとうまく相互運用できるといいのだが
    標準Rubyやgemをパッケージ化・バンドルする方向では、今でもtebako、kompo、ocranが必要で、以前にはruby-packer、traveling ruby、jruby warblerのようなプロジェクトもあった
    選択肢がひとつ増えるのは良いことだが、より良い開発者UXを備えた 決定版 が出てきてほしいと思っている

    • そう、その通りで、私も最近 warbler をforkしなければならなかった
      あまりにも長い間更新されていなかったからだ
  • なぜ no threads なのか気になる
    Ruby schedulerと下層のpthread実装はC側でもうまく動きそうだし、もしかしてzero dependencyを狙ったのだろうかと思う
    optional extensionとして後から入れる予定なのか、それとも単にまだ外してあるだけでないなら、この選択は少し奇妙に感じる

    • これを意図的に サポートしないと決めた という根拠はまだ見ていない
      たぶん、まだそこまで到達していないだけではないだろうか
      マルチスレッドはもともときちんと作るのが非常に難しい
  • 1か月少々で作ったというのは驚きだ
    AIについて何と言おうと、腕のある開発者 の手に渡ればとてつもない速度向上を生み出す

    • 業界全体ではagent harness、SOUL.md、権限設定、skills、MCPs、hooks、envを全部そろえて始めるのに、
      Matzはただ gem env|infofind だけで十分そうに見える
  • これがMatzの作ったものだとなると、今後 Ruby core の一部になる可能性がどれくらい現実的なのか気になる
    そして、そうなった場合Crystalにとってどれほど脅威になるのかも気になる

    • Crystalには明示的な static type system があり、言語レベルでAOTコンパイルに最適化されている
      こうした特性は大きなプログラムをコンパイルし、保守するうえで事実上不可欠に近い
      一方こちらは制限されたRuby subset向けなので、人気のあるRuby gemの多くはそのままでは動かないだろう
      Cコンパイルを志向する言語subsetという点では PreScheme により近く見える
      現時点では、両者が同じ領域で直接競合しているとは思わない
      完全なRubyにはほぼ確実にJITが必要だ
      [1]: https://prescheme.org/
    • 別の見方をすると、結局LLMが私たちの望むどんな言語に対しても formal specification を吐き出す地点に到達するのだと思う
      Rational Unified ProcessやEnterprise Architectの復讐が始まるようなものだ
      違いがあるとすれば、UMLダイアグラムの代わりにmarkdownファイルが来るくらいだ
  • これは infrastructure tools の分野で役立ちそうだ
    たとえばRubyで書かれていながら静的コンパイルされるbundlerがあって、RVMのようなRubyインストールツールの役割まで兼ねる、と想像できる
    既存のRuby buildpackはRubyで書かれているが、ブートストラップをbashでやらないといけないので面倒だし、edge caseも生まれる
    CNBはその問題を避けるためにRustで書かれており、依存関係のない単一バイナリ を配布できるという発想は本当に強力だ