汎用 VM という賭け — Parrot はなぜ誰のものにもならなかったか

Parrot は「動的言語共通の VM」を目指した。Perl 6 も Python も Ruby も Tcl も載る基盤を作る、という賭けである。前提は成立しなかった。本気の利用者が Perl 6 だけだったため、汎用性のために払ったコストを回収できなくなった。2013 年、Rakudo は MoarVM へ移る。汎用性を捨てて専用に振ったことで、初めて完成した。

perlrakuparrotmoarvmvmlanguage-implementationprogramming-languages

前回、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 へ移す。

MoarVMMetamodel 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 を通ることである」という形に移った。 その判断が何を可能にし、何を手放したのか。

← Back to Perl と Raku の系譜