2026年7月15日、Roc プログラミング言語の創設者 Richard Feldman が一篇の技術ブログを公開し、彼らが487日をかけて30万行の Rust コードを Zig に書き換えたと発表した。コンパイラのインクリメンタル・ビルド時間は3.4秒から35ミリ秒へ——丸ごと100倍も速くなったのだ。
これは孤立した出来事ではない。それ以前にも、Gleam 言語のコンパイラが同じ道を辿っている:Rust から Zig へ。一方で Bun ランタイムは、2026年初めに逆向きの操作を済ませていた——Zig から Rust へ、わずか11日で。
両極のトップクラスのコンパイラ開発者が、真逆の方向に截然とした選択を下した。ある事柄の表裏両面に、本物のコードで誰もが票を投じた時、あなたは知る:これの裏には天秤の問題があると。

35ミリ秒って、そもそも何を意味する?
3.4秒でも十分速い。筆者は Rust で幾つかのプロジェクトを書いてきたが、cargo check が二三秒回り、rust-analyzer がバックグラウンドでぶんぶん言う——正直、慣れれば慣れるものだ。Rust のコンパイル速度は過去18ヶ月で飛躍的に向上し、Rust 1.97 は 1.85 に比べインクリメンタルビルドを三分の二に削った。Feldman 自身も記事の中で Rust チームのその努力を心から賞賛している。
だが35ミリ秒は別の生き物だ。
35ミリ秒とは、Ctrl+S を押した瞬間——指がキーボードからまだ離れる前に——コンパイラがもう結果を告げているということだ。これがフィードバック・ループの消失だ。Zig チームのメンバー mlugg は、Lobsters でこの体験を語り、一つのディテールを挙げている:彼のインクリメンタルビルドは一回あたり30ミリ秒程度で、そのうちリンカの仕事はわずか1ミリ秒ほど。なぜなら Zig の新しい ELF リンカは、単一の関数を粒度とするインクリメンタル・リンクを想定して設計されている——一つの関数を直せば、コンパイラが新しい機械語を生成し、リンカが出力ファイルの .text セグメント内で旧コードの位置を探して上書きする。syscall は不要だ、出力ファイルは mmap でメモリにマップされているからだ。
この「ゼロ待ち」は、開発者とコンパイラの関係を変えた。もはや修正をまとめてからビルドを一回回す必要はなく、修正とフィードバックの間を素早く試せる——まるでインタプリタ型言語を使うようにコンパイル型言語を使うように。Roc コンパイラの新バージョンはホットコード・ロードさえサポートする:動作中のサーバがプロセスを改善せずとも、修正後のコードへ自動で切り替わる。これは Python の世界では標準だが、コンパイル型言語の世界では贅沢品だ。
では、Rust の型安全は一体どこが「高い」のか?
35ミリ秒が Zig からの甘味だとすれば、Rust が徴収する「安全税」はどれほど高いのか? この問いは分解して見る必要がある。
一つ目の勘定:コンパイル時間。 Rust の borrow checker はコンパイル時に極めて贅沢なことをする——プログラムに use-after-free も double-free もデータ競合もないことを証明する。この証明プロセスはプログラム全体の参照関係グラフを辿る必要があり、複雑度はコード規模に対し超線形に増大する。Rust のインクリメンタル・コンパイルは絶えず進歩しているが、borrow checker の本質が、それを Zig のように「即出」にすることは不可能にしている。
二つ目の勘定:アーキテクチャの自由度。 Roc コンパイラは arena アロケータと struct-of-arrays レイアウトを多量に使っている——全てのデータ構造が32ビットのインデックスでポインタを置換し、フィールドごとに独立した配列に分割されている。このスタイルは現代の CPU 上で猛烈に速く、さらにディスクへ直接 mmap して「ゼロ解析のシリアライゼーション」を実現できる——二回目の roc check では、解析済みのデータ構造がすべてディスクからそのままメモリへ飛び込み、速度は memcpy に近い。
だが問題は:このプログラミング・スタイルは、ほぼ確実に Rust の borrow checker と衝突する。arena+インデックスのパターンは Rust の所有権システムを迂回するため、unsafe の割合が典型的な Rust プロジェクトをはるかに上回ることになる。Feldman のチームは30万行の Rust コードの中に約1200箇所の unsafe を持っていた——これは rustc コンパイラ自身の unsafe 密度より一桁高い。unsafe が「少数の監査が必要な隅」から「至る所に遍在する常態」になると、borrow checker がもたらす安心感は割引かれる。
両側の勘定簿:数字は嘘をつき、また真実を語る
Feldman は誠実なことを一つした:コンパイラの二つのバージョン各自の、メモリ破壊バグの数を統計した。
Rust 版:21個。Zig 版:10個。
一見、Zig の勝ち。だが仔細に分解すると——Rust 版の21個のメモリ破壊バグはすべて miscompilation(コンパイラが誤った機械語を生成した)であり、コンパイラ自身のロジック内で起きたものは一つもない。borrow checker は為るべきことを為していた。Zig 版の10個のうち、8個もまた miscompilation で、残る2個は use-after-free——いずれもエラー報告がファイル名をレンダリングする箇所で、症状はエラーメッセージ内のファイル名が文字化けするというものだった。
Feldman の結論は、意外なほど静かだ:「18ヶ月の開発、数百のバグ報告、数十万行のコードを振り返って、私の主な感想は:どちらを選んでも同じだ、ということだ」。あの2個の use-after-free は、Rust の borrow checker なら防げ、Zig の ReleaseSafe モードなら実行時に panic する——だが三つの案の実際の影響はいずれも「二つのバグ報告:いくつかのエラーメッセージでファイル名が表示されない」であった。
この結論は Bun チームのものと微妙に対照する。Bun が Zig から Rust へ移行する際、JavaScript の GC 値と手動メモリ管理を同時に扱う必要があるプロジェクトにとって、use-after-free は「大量のバグの源」だと強調した。Feldman はこれに完全に同意する——そして、Roc のコンパイラは JavaScript との相互運用を必要としないと指摘する。
決定的なのはどちらが正しいかではない。決定的なのは:文脈がすべてを決めるという点だ。

コミュニティの裂け目:これは聖戦ではない
この記事は Lobsters で175ポイント・62コメントを、Hacker News でも激しい議論を呼んだ。だが最も注目すべきは、両側ともに第一線からの、筋の通った論拠を持っていることだ。
Rust コアチームの Ralf Jung は、Feldman が引用した「rustc に4万箇所の unsafe がある」という数字の問題を指摘した——この数字は標準ライブラリやテスト、コメント内の出現回数を含んでおり、実際のコンパイラ内の unsafe はこれよりずっと少ない。彼は同時に認めている:「unsafe Rust を正しく書くのが難しいという点には完全に同意する。それは私が非常に懸念している問題だ」
llogiq——compact_arena crate の作者——は、Rust の型タグ・システムがコンパイル時に異なる arena のインデックスを区別し、「間違った配列を使う」問題を避けられると指摘した。だがまた、この技術が arena の数がコンパイル時に未知なシナリオでは確かに効かなくなるとも認めている。
aapoalas——自らを「データ指向設計の狂信者」と称する Rust ユーザー——は典型的な矛盾した心境を表した:“As a data-oriented design zealot and an avid Rust user: it’s sad seeing a like-minded project moving away from Rust.” 彼はその後、Rust で同様の最適化を実現するために自分が試した一連の取り組みを挙げ、そこには「諦めきれない」という誠実さが滲んでいた。
筆者は思う、この論争の健全なところは:誰も相手を馬鹿と呼ばないことだ。誰も「Rust を選ぶのは性能を分かっていない」とか「Zig を選ぶのは安全を顧みない」とは言わない。皆がこれが本物のトレードオフであると認め——そして各自のプロジェクトの文脈に基づき異なる選択を下している。
もう一層深い対決:comptime vs proc macro
コンパイル速度の数字遊びの裏には、もう一つ味わい深い哲学的な分歧がある:コンパイル期のメタプログラミングを何で行うか?
Zig の選択は comptime——書くのは普通の Zig コードで、それがコンパイル期に実行されると印を付けるだけだ。それはコンパイラに内蔵されたインタプリタのようで、ジェネリック・プログラミングもコード生成も型操作も、実行時のコードを書くのと同じように自然になる。二番目の構文はなく、token tree の操作もなく、衛生マクロの癖もない。
Rust の選択は proc macro——コンパイル期に実行される独立した Rust プログラムで、token ストリームを受け取り、操作し、出力する。それは極めて強力だ(理論上何でもできる)が、極めて重いでもある。各 proc macro は独立した crate であり、それ自身をコンパイルするにも時間がかかる。Zig の comptime は同一のコンパイル・プロセスに内包され、ほぼ追加コストはない。
これが Zig が速い隠れた理由だ:マクロ・システムを先にコンパイルし、その後あなたのコードをコンパイルする必要がない。メタプログラミングと主プログラムは同じコンパイラ・パイプラインを共有する。Feldman は記事でこう言っている:「I love that Zig doesn’t have macros.」——この言葉単独では愚痴に聞こえるが、文脈と合わせれば、一種の引き算の美学を表している:仕組みが一つ減れば、抽象が一層薄れ、コンパイルの負担も一つ減る。
もちろん引き算は喪失を意味する。Feldman も Rust の trait システムと private フィールドを恋しく思うと認めている。これらは Rust が足し算で得た表現力だ。Zig を選ぶとは、「表現力」より「単純さ」を重んじることを受け入れること——少なくともコンパイル速度を命綱とするプロジェクトにとっては。
筆者の判断:魚と熊手だが、皿は選べる
これはどちらかを担ぐ記事ではない。筆者が以上の分析を書き終えた時の率直な感想は:Rust と Zig の関係が、「どちらが優秀か」から「どちらが何に適しているか」へと変わりつつある、ということだ。
もしあなたのプロジェクトが Web サーバやデータベースのように——コード構造が比較的安定し、unsafe が少数のホットスポットに集中し、長期的な信頼を borrow checker に頼るなら——Rust は今もっとも安全な選択だ。
もしあなたのプロジェクトがコンパイラのように——コードが頻繁に反復リファクタリングを要し、unsafe が至る所に遍在し、コンパイル速度が思考のリズムに直結するなら——Zig は無視できない選択肢になりつつある。なぜならこの種のシナリオでは、安全のコストの値付けが異なるからだ。
Roc チームがやったのは、彼らに必要な安全の型を再定義することだ。彼らのメモリ安全問題は主に生成された機械語にあり、コンパイラ自身ではない——そして borrow checker は前者にはそもそも届かない。安全の隘路が言語が提供する保証の範囲外にある時、そのためにコンパイル時間を払うコストは、もはや商量の余地があるものになる。
35ミリ秒と3.4秒の差は、本質的に二つの開発哲学の具象化だ:一つは機械がコンパイル期にすべてを証明できると信じ、もう一つは開発者が実行期にすべてをうまく管理できると信じる。どちらも完璧ではない——だが少なくとも今、開発者には真に異なる選択肢がある。
これはおそらく、システムプログラミングここ数年で最良の知らせだ。
参考リンク:
- Richard Feldman:『How Our Rust-to-Zig Rewrite is Going』(2026年7月15日)
- Lobsters 議論:How Our Rust-to-Zig Rewrite is Going(175ポイント/62コメント)
- Bun チーム:『Why We’re Rewriting Bun from Zig to Rust』(2026年)
- Zig 公式開発ログ:Incremental Compilation Demo
- Gleam 言語 FAQ:Why Rust for the compiler?