
2026/07/16 20:39
Rust から Zig への書き換えの進行状況
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
Roc プログラミング言語のチームは、開発期間 487 日を費やしてコンパイラー全体を Zig に書き換えに成功し、新たなツールチェーンが元の Rust ベースのバージョンとの機能同等性を達成したという重要なマイルストーンに達しました。即時的な主要な利点の一つとして、デモゲーム(例えば「Rocci Bird」)におけるバイナリサイズの劇的な削減と、コンパイル速度への飛躍的な向上があります。増分ビルドは現在 3.4 秒からわずか 35 ミリ秒で完了しており、これは約 464K 行のコードに対して該当します。この新しい Zig ベースは、パターン一致内の文字列補間を用いたゼロ割当ルーティングロジックや、自動ホットコードリロードなどの強力な機能を実装することを可能にしています(例:
/users/${id})。これにより、外部依存関係なしでメモリ使用量を最適化することが可能です。この書き換えは Rust の利便性の一部(例えば安定した互換性の確保や自動テストのための割当)を犠牲にしますが、粒度の細かいメモリアロケーターサポートを獲得し、WebAssembly および Alpine Linux 環境において理想的な独立型バイナリを作成しました。チームはプライベート構造体フィールドやマクロなどの機能におけるトレードオフを認めつつも、Zig が提供するデータレイアウトに対する制御力および unsafe コードへの支援を高く評価しています。今回の書き換えは Bun のポートが要した 11 日と比べて大幅に長期化しましたが、これは Roc が広範な内部変更を必要としたためです。それでも既に特定領域(例えば誤コンパイル versus ロジックエラー)でのバグ減少を実現しており、今年の後半に公式のバージョン 0.1.0 のリリースを目指すとともに、現時点では不完全ですが有望な機能をテストするための夜間ビルドが利用可能です。本文
ロック(Roc)コンパイラ改稿レポート:Rust から Zig へ
ロック(Roc)のチームは過去1 年半以上をかけ、約30 万行に及ぶ Rust コードを完全に Zig に書き換えました。 このプロジェクトの目的と背景、機能の実装状況、そして言語選択の根拠について詳しく解説します。
🚀 マイルストーン:機能の平等(Feature Parity)達成
改稿が完了し、新コンパイラは元の Rust ベースのコンパイラと機能的に同等となりました。これにより、Roc コードで書かれた WASM ゲーム「Rocci Bird」を新環境での動作確認が可能になりました。
🎮 Rocci Bird の実績
- 実装例: 全ソースコードが1,000 行未満の簡潔なゲーム。
- サイズ削減:
コマンドで生成された WASM バイナリは31KBに压缩されました(旧コンパイラはこれよりも倍以上大きかった)。roc build --opt=size - 動作確認: itch.io で遊べます。WebAssembly 経由でもブラウザで即座に実行可能です。
-
ゲームをクリック/タップし、スペースキーで翼ばたきを行ってください。(モバイル版では右矢印キーがないため、リフレッシュして再開始してください)
-
🙏 感謝の言葉
公式リリース(0.1.0 版、目標:今年後半)以前ですが、達成したことに感謝します。特に以下の貢献者に謝意を表します。
- Anthony Bullard & Sam Mohr: 新しいパーサーの共同開発
- Jared Ramirez: 新しい型チェッカーなど多機能実装
- Ayaz Hafiz: 新しいラムダセット解決システムと旧コンパイラの引き継ぎ
- Aurélien Geron: 108 問の練習問題(Roc Exercism)を手作業でアップデート
- Stephan: ブラウザ上で動作する「echo」プラットフォームの実装(2.5MB の WASM ベイナリ利用)
- Niclas Åhdén: 有益なバグ報告と具体的なフィードバック
- JRI98: ファッザ誤差の再現・調査と修正
- Jasper Woudenberg: ユーザースペースパッケージ API の改善
- 基礎構築者たち (Folkert de Vries など): 元コンパイラを築いた方々への感謝
- 最大の貢献者: Anton-4 と Luke Boswell
- コンパイラワーク、ビルトイン関数、プラットフォーム作成など多大な支援に心から感謝します。
注記: Bun プロジェクトは Zig から Rust へ約 50 万行を 11 日間で書き換えました。我々は Rust から Zig への約 30 万行を書き換えましたが、487 日(約 16 ヶ月)かかりました。言語の違いだけでなく、プロジェクト規模や変更範囲の違いが理由です。
✨ 新しい機能の実装
🔥 ホットコードロード & クロスコンパイル
新コンパイラは開発中でもホットコードロードを自動実行します。
- 動作:
でサーバー起動中にソースを修正すると、リクエスト処理時に即座に反映されます。roc server.roc - クロスコンパイル:
コマンドで Alpine Linux 用の静的バイナリを作成可能です(Mac など他 OS でも同様の出力サイズ)。roc build --target=x64musl
🧵 文字列埋め込みを持つパターンマッチング
新機能「パターンマッチング内への文字列埋め込み(String Interpolation)」を実装しました。
match (verb, path) { ("GET", "/users/${id}/${page}") => match page { "" | "profile" => ok(id) "settings" => ok(with_default(user_agent, id)) "posts/${post_id}" => ok("Post ID: ${post_id}") _ => not_found } // ... 他のケース }
- 特徴: ランタイムでのテンプレート解析ではなく、コンパイル時の言語機能として実装。
- 利点: 型安全かつゼロのヒープ割り当て。Hot Code Loading の環境下でも安定しています。
📖 詳しく知りたい方はRoc Zulipをご覧ください。
❓ なぜ「スクラッチ・リライト(Scratch Rewrite)」なのか?
🔍 背景:メモリ割り当てとデフォニクショナライゼーション
Roc はシステム言語ではなく、参照カウントによる自動メモリ管理を持っています。
- 既存の課題: クロージャキャプチャ時のヒープ割り当て数が多すぎること。
- 解決策: 非学術的な言語として初めて**「多态な defunctionalization(ラムダセットの専門化)」**を導入し、クロージャキャプチャをヒープに割り当てないようにしました。
🛠 アーキテクチャ的再構築の必要性
この最適化は複雑で、元のコンパイラでは重大なバグが生じていました。OCaml によるプロトタイプを作成した Ayaz Hafiz が示した通り、根本問題は**「複数のコンパイラフェーズにまたがるアーキテクチャ」**にありました。
- 一部を直すだけでなく、コンパイラの一部を再構築する必要があることを認識。
- コンパイラ自体を自言語(Roc)で自己ホストするのは異例ですが、書き換えの利点がコストを上回るケースが存在することを理解しました。
🆚 なぜ Zig を選んだのか?
Rust ではなく Zig を選ぶ決定要因は以下の通りです。
1. ビルド時間の大幅短縮
- Cargo のインクリメンタルビルドはコード増加と共に遅化していました。
- Zig に書き換えることで、ビルド時間を劇的に短縮できました(後述)。
2. メモリ制御の柔軟性
- Rust: 単一のグローバルアロケーター前提。
- Zig: 粒度細やかなアロケータ前提。**構造体配列(SoA)**レイアウトが標準でサポート。
- コンパイラ開発には、特定の領域ごとにメモリを制御する需要が高いため、Zig のモデルに合致します。
3. エコシステムの適応性
- Rust は大規模ですが、我々のようなニッチな最適化(LLVM ビットコードの高速出力など)については Zig にすでにコードが存在しました。
4. メモリ非安全性への対応
- Rust は
を最小限に抑えようとする文化があります。unsafe - しかしコンパイラ開発では**メモリ非安全なコード(FFI やライブラリ互換など)**が避けられません。約 1,200 の
ブロックが必要でしたが、Zig はこれらをより自然に扱える設計です。unsafe
🛡️ 改稿後のメモリー安全性検証
脆弱性内訳と ReleaseSafe/ReleaseFast
Microsoft の調査によると、メモリセキュリティ脆弱性の多くは使用後フリー(UAF)などです。
- ReleaseSafe: ランタイムチェックあり(パニック発生可能)。TigerBeetle DB で実証済み。
- ReleaseFast: テスト・デバッグ用。生産環境ではチェックをスキップ(オーバーヘッド削減)。
バグレポートの比較表
| カテゴリ | Rust 版 (旧) | Zig 版 (新) |
|---|---|---|
| メモリ腐敗が起きたバグ | 21 | 10 |
| メモリ腐報が発生しなかったバグ | 2,575 | 421 |
| 合計 | 2,596 | 431 |
- 重要な事実: Rust 版の 21 のバグはすべてコンパイラロジック以外(コンパイルされたプログラムの動作)で発生していました。ローバーチェッカーが正常に機能していた証左です。
- Zig 版の 10 バグのうち、8 は誤コンパイル(UAF エラー)、2 はコンパイラ自体のものでした。
ツールの選択による影響
異なるツール設定でも顕著な違いはみられませんでした。
| ツール選択 | 結果 |
|---|---|
| Zig ReleaseFast (標準) | 2 バグ(ファイル名レンダリング不具合) |
| Zig ReleaseSafe (厳格) | 2 バグ(パニック発生、レンダリング不具合) |
| Rust ローバーチェッカー | 0 バグ(検知不可能な場合を含む) |
結論: Bun のように「手動管理メモリと GC の混合」が主課題の場合とは異なり、Roc はそのリスクが少ないため、ReleaseSafe/Rust ロワーチェッカーほどの厳密なチェックはプロジェクトに対して必須ではありませんでした。
⚡ ビルド時間の改善結果
| コンパイラ | LoC (行数) | 冷たいビルド | インクリメンタル |
|---|---|---|---|
| Rust 1.85.0 (改稿前) | 354K | 32.4s | 10.0s |
| Rust 1.97.0 (改善後) | 354K | 25.4s | 3.4s |
| Zig 0.16.0 (機能平等時) | 320K | 39.6s | 8.6s |
| Zig 0.17.0 (現在) | 464K | 32.1s | 0.035s |
- インクリメンタルビルド: Rust で改善されれば 10 秒→3.4 秒でしたが、Zig ではさらに35 ミリ秒まで短縮できました。
- ゼロパースデシリアライゼーション: アリーナベースのデータ構造により、ディスクからメモリへ読み込む際の手間(パージ)を省略。I/O ボトルネックを回避する高速化を実現しています。
🍂 Rust から欠けているもの
Rust の世界に戻る際に恋しく思う点があります。
- 自動割り当てと解放: 手動管理が必須の Zig では、テストでメモリリークを検知するテストアロケータの記述が大変です(Rust では不要)。
- 適応型多態性 (Comptime): パラメトリックな型定義よりも、コンパイル時の値計算機能の方が実用的。
- プライベート構造体フィールド: 防御的コーディングを助ける機能がないため、ドキュメント参照が難しい。
- スネークケース命名: Rust の
プレファレンスの方が直感的。snake_case - 逆方向互換性: Rust のマイナーリリースにおける平滑なアップグレード体験は素晴らしいです。
🌟 Zig で気に入っていること
- 関数型プログラミングの純粋さ: 突然変異や制限されない副作用など、ツールボックスの使いやすさを実感。
- マクロがない: シンプルさと予測可能性が高い。
- データレイアウトへの直接アクセス:
やu7
といった特殊サイズやビット操作が容易。u5 - ビルドツールチェーンの独立性: Alpine Linux や WebAssembly 用の自立型バイナリ作成が可能。
- エラー処理: エラーは自然に蓄積し、失敗したヒープ割り当てを通常のユーザースペースエラーとして扱う戦略が好き。
🔮 ロックの今後の展望
- 目標: 今年後半にバージョン 0.1.0(初の番号付きリリース)をリリース予定です。
- ナイトリービルド: リリース直前の最新ビルドを試すことができますが、バグや不完全な機能がある可能性があります。
- 寄付受入れ: ロックプログラミング言語財団は 501(c)(3) 団体であり、寄付には税制優遇があります(コントリビューターの活動支援に充てています)。
みなさまの貢献に感謝いたします。 言語の助けをかりて新しいマイルストーンを達成できました。次の目標である最初の正式リリースに向けて、さらに多くの機能を強化してまいります!
- 質問や意見は Roc Zulip でお気軽にチャットしてください。