汎用 VM という賭け — Parrot はなぜ誰のものにもならなかったか
Parrot は「動的言語共通の VM」を目指した。Perl 6 も Python も Ruby も Tcl も載る基盤を作る、という賭けである。前提は成立しなかった。本気の利用者が Perl 6 だけだったため、汎用性のために払ったコストを回収できなくなった。2013 年、Rakudo は MoarVM へ移る。汎用性を捨てて専用に振ったことで、初めて完成した。
前回、Pugs が「動くものがあること」の価値を証明した話を書いた。 今回はその裏側 — Perl 6 が実装基盤の選定で一度賭けを外した話である。
名前の由来はエイプリルフール
2001 年 4 月 1 日、こういう冗談記事が公開された。
Larry Wall と Guido van Rossum が Perl と Python を統合し、 Parrot という新言語を作る。
Monty Python のオウムのスケッチにかけたジョークだ。
後に Perl 6 の VM が本当に作られることになったとき、この名前が採用された。 この由来自体が、Parrot の目標をよく表している。 1 つの VM で複数の動的言語を動かす、という発想である。
設計上の賭け
Parrot は Perl 6 専用の VM ではなかった。動的言語一般のための VM を目指した。 想定していた対象は Perl 6、Perl 5、Python、Ruby、Tcl、PHP、Scheme など。
主要な設計判断はこうだ。
| 判断 | 理由 |
|---|---|
| レジスタ機械(スタック機械ではない) | 動的言語の最適化に有利という読み。JVM / CPython はスタック機械 |
| PMC(Polymorphic Container) | 言語ごとに異なる値の意味論を、共通の器で扱う |
| 継続を第一級で持つ | コルーチン・例外・動的スコープを統一的に扱う |
| 豊富な組み込み型 | 各言語の実装者が VM 側の部品を使い回せるように |
主導したのは Dan Sugalski(チーフアーキテクト)。 後に Allison Randal らが引き継ぎ、2008 年に Parrot Foundation が設立された。 Parrot 1.0 は 2009 年 3 月にリリースされている。
これは真剣な、そして知的に魅力的な設計だった。 後知恵で笑うべきものではない。動的言語の実装に共通する仕事は確かにあり、 それを 1 か所にまとめるという発想は正しい形をしている。
何がうまくいかなかったか
1. 本気の利用者が Perl 6 だけだった
「複数言語の共通基盤」という前提が成立しなかった。
Python も Ruby も、既に自前の実装があり、それぞれ独自に改良を進めていた。 Parrot に載せ替える動機が無い。既存の C 拡張も、既存の性能特性も、既存のコミュニティもある。
結果として、汎用性のために払ったコストに対して、汎用性の見返りが無い状態になった。
Perl 6 専用に作ればしなくてよかった抽象化を、ずっと背負い続けることになる。 PMC の間接層も、言語中立な呼び出し規約も、 「他の言語が来たときのため」に存在していて、その他の言語は来なかった。
ここに、この連載で 6 つ目の「型」がある。
1 人目の利用者では、汎用のふりを見抜けない。
2 人目が来るまで、その抽象化が本当に汎用かどうかは検証されない。 Parrot は 2 人目が来なかったために、汎用性が検証されないまま重くなった。
厄介なのは、この状態が失敗として見えにくいことだ。 Parrot は動いていた。Rakudo は Parrot の上で動いていた。 「汎用性が回収できていない」は、テストが赤くなる類の問題ではない。
2. 性能が出なかった
レジスタ機械という賭けは、期待したほどの差を生まなかった。 GC、呼び出し規約、PMC のディスパッチ — 各層のオーバーヘッドが積み上がり、 Rakudo on Parrot は実用には遅いという評価が長く続いた。
「Perl 6 は遅い」という評判が定着したのは、主にこの時期である。 そしてその評判は、基盤が入れ替わった後も長く残った。
3. 仕様が動く相手に合わせ続けた
Perl 6 の仕様が固まっていない時期に VM を作っていたため、 上の要求が変わるたびに下を作り直すという往復が発生した。
前回書いた「実装が仕様を動かす」往復(Pugs が始めたもの)は健全な機構だが、 その往復が VM 層まで届くと、コストの桁が変わる。
清算 — 2013 年、MoarVM
2013 年、Rakudo は主力バックエンドを MoarVM へ移す。
MoarVM(Metamodel On A Runtime)は、 主に Jonathan Worthington が主導した C 製の VM である。
Parrot の教訓が、設計方針にそのまま出ている。
| Parrot | MoarVM |
|---|---|
| 複数の動的言語のための汎用 VM | NQP / Rakudo 専用と割り切る |
| 言語非依存の抽象を持つ | Raku のオブジェクトモデル(6model)を VM が直接知っている |
| 汎用性のコストを常に払う | Raku が要るものだけを最適化する |
「汎用 VM を作って Perl 6 を載せる」から「Perl 6 のための VM を作る」への転換。
これが、Perl 6 が完成に向かった技術的な転換点である。 2 年半後の 2015 年 12 月に 6.c が出るのは、この判断があったからだ。
専用に振ったから入れられたもの
MoarVM の特徴を見ると、「専用だから可能だった」ものが並ぶ。
NFG 文字列 — MoarVM は文字列をグラフェム単位で持つ。
my $s = "a\c[COMBINING ACUTE ACCENT]"; # a + 結合アクセント
say $s.chars; # 1
「見た目の 1 文字」が .chars の 1 になる。
他の言語と並べると、Raku の立ち位置がはっきりする。
| 言語 | 文字列の単位 |
|---|---|
| C | バイト |
| Java / JavaScript / C# | UTF-16 コードユニット |
| Python 3 / Go(rune) | コードポイント |
| Ruby | コードポイント(エンコーディング付き) |
| Raku | グラフェム |
言語中立な VM では、この選択はできない。 「文字列とは何か」について特定の立場を取ることになるからだ。 専用 VM だから入れられた。
他にも、6model をネイティブに扱うこと、spesh(実行時の型情報による特殊化)、 JIT、精密 GC、libuv による非同期 I/O — いずれも 「Raku が必要とするもの」に照準が合っている。
Parrot をどう位置づけるか
「失敗」と一言で書くのは正確ではない。実際に残ったものがある。
- Perl 6 が実際に動く最初の道筋を作った — Rakudo は Parrot の上で生まれた
- 中間表現の設計経験が、NQP の設計に活きている
- 複数バックエンドを持つという発想が、NQP のバックエンド中立設計として生き残った
正確な要約はこうだ。
賭けの前提(複数言語が乗る)が外れ、 そのために払っていたコストが回収できなくなった。
バックエンドは何本まで維持できるか
そして、Parrot の教訓を受け継いだはずの NQP にも、同じ問題の影がある。
NQP は Raku のサブセットで、複数バックエンドを持つ設計だ。 新しい VM に対応したいとき、NQP だけを移植すれば Rakudo がついてくる。 理屈としては美しい。
実際はこうなっている(2026 年 9 月時点)。
| バックエンド | 状況 |
|---|---|
| MoarVM | 事実上の唯一の実用バックエンド。既定 |
| JVM | 動くが機能・性能とも追随が遅れている |
| JavaScript | 実験的。実用水準に達していない |
理由は技術ではなく人員である。 バックエンドを 1 つ維持するコストは高い。複数を同水準で維持するには、 それぞれに継続的な担い手が要る。Raku の規模ではそれが成立しなかった。
ここから、7 つ目の型が出る。
バックエンドが N 本あることと、N 本が検証されていることは別である。
2 本目に本気の利用者がいない限り、中立に書いたつもりの層は、 いつのまにか 1 本目の都合に合っている。
ここは他人事ではない
私は自分で言語を作っていて、バックエンドを 5 本持っている (インタプリタ・C・LLVM IR・Wasm・RISC-V 機械語)。
Parrot と NQP の話を調べていて、自分がやっていることの名前が付いた感覚があった。 5 本あることは、5 本が検証されていることではない。
私の場合、それを一応防いでいるのは、インタプリタをオラクルにして、 他の 3 本の出力をバイト単位で突き合わせる仕掛けを持っていることだ (5 本目の RISC-V は QEMU の下で起動させて確かめる)。 「中立に書いたつもり」を、実際に走らせて比べる。
しかしこの仕掛けにも穴がある。オラクル自身が間違っていたら、5 本揃って間違う。 Parrot が「汎用性が回収できていない」ことをテストで検出できなかったのと、 種類としては同じ問題だ。
だからこの連載の次回のテーマは、私にとっても切実である。 仕様とは何か。何をもって「正しい」と言うのか。
次回(第 7 話): 仕様をテストスイートで定義する。 Perl 6 は散文の仕様を捨て、「仕様とは roast を通ることである」という形に移った。 その判断が何を可能にし、何を手放したのか。