Ruby30周年イベント(後編):まつもと氏「Static Compiler for Ruby」を作りたい。道具立ては揃ってきた
今回は「Ruby30周年イベント(後編):まつもと氏「Static Compiler for Ruby」を作りたい。道具立ては揃ってきた」についてご紹介します。
関連ワード (収集、実現、気持等) についても参考にしながら、ぜひ本記事について議論していってくださいね。
本記事は、Publickey様で掲載されている内容を参考にしておりますので、より詳しく内容を知りたい方は、ページ下の元記事リンクより参照ください。
まつもとゆきひろ氏によって開発が始まったRuby言語の30周年を祝うイベント「プログラミング言語Ruby30周年記念イベント」が2月25日にオンラインで開催されました。
イベントでは関係者やRuby愛好家らによる過去30年の振り返りやRubyにまつわるライトニングトークなどが行われ、最後にまつもとゆきひろ氏による基調講演「D is for Dream, V for Vaporware」が行われました。
基調講演では、Rubyを開発する前にまつもと氏が手がけた、Rubyの原点となるソフトウェア「CXライブラリ」や、今回初めて名前が明かされた「Tish」という作りかけのプログラミング言語や、これまであまり語られることのなかった、さらにその前の学生時代に妄想していたプログラミング言語「Alpha」や、そもそもプログラミング言語の開発のきっかけとなった小説についても紹介されました。
そしてこれから作りたいものとして、まつもと氏は「Static Compiler for Ruby」を挙げ、そのための道具立てが揃ってきたこと、そしてRubyのような暗黙的型言語の可能性と、そしてまだ作られていないRubyのサブセット言語を「スピネル」と命名するなど、これからのRubyの夢を語りました。
この記事ではその基調講演の内容を紹介します。記事は前編、中編、後編の3つに分かれています。いまお読みの記事は後編です。
外見は過去と同じでも中身は最新になっている
Rubyのソースコードのうち、実際に私が書いた部分がどのぐらい残っているかを2年ぐらい前にカウントした時点では1割ぐらいだったんですね。
それからJITなども増えてたりするので、今はたぶん1割以下、5%から7%ぐらいあればいい方ですね。
今のRubyのソースコードは何十万行もあるんですけれども、私はRubyを作ったと言いつつ、実際に私が作ったRubyのコードはもう1割を切っているんですね。
そうするともう、私の作ったRuby、みたいな感じではないんですね。外見は同じでも中身は最新になっている。
宇宙戦艦ヤマトとか銀河鉄道999みたいに外見は古めかしい軍艦であるとか古めかしいSL機関車であるけれど、中身は最新であるって感じで、すごい松本零士的な感じのね、構造を持っているんじゃないかなという気がします。本当に惜しい方を亡くされたと思いますけれども。
この傾向はこれからも変わらず継続するつもりです。つまり、次々と起きてくる現代ならではの問題を解決するんだけど、外観っていうんすかね、それはさほど変わらないと。
これからのRubyは、外見は同じで言語仕様は大体同じなんだけど、文法もちょっと拡張するかもしれないし、ライブラリも拡張するかもしれないし、既存のライブラリにメソッドがちょっとずつ増えることもあるかもしれない、かつ、Rubyを取り巻く文化というものも段々変化していくかもしれない、と思ってます。
Rubyを取り巻く、あるいはRailsを取り巻く文化もどんどん変化していくので、それに伴ってRubyの取り巻くコミュニティが生成していくコードそのものも変化していくだろうというふうに思います。
それに伴ってGemであるとか、Railsとか、そういうものもどんどん進化していくだろうと思います。
さらにRuby 3.0以降、ツールの充実は非常に強く強く訴えてきましたし、それに応えてTypeProfやRBSやRuboCopなど、さまざまなツールが充実してきました。
あるいはLanguage Server Protocolのruby-lspみたいなものも強化されてきて、VSCodeで開発していると、TypeScriptにはまだ追いついていないけれども、補完されたりするようになってきました。
さらにRubyの性能もずいぶん向上しました。
これからもRubyの着実な変化は続けていくべきだと思ってるんですね。
ただ、ただですよ、着実な変化だけだと面白くないんですよね。
もしかしたら失敗するかもしれないけれどチャレンジする、成功したら儲けもの、みたいなものがコミュニティに存在しないと、参加してて面白いコミュニティにならないんじゃないかな、と思って。
少し前だとYJITの存在そのものが、MJITよりも遥かに速いJITコンパイラをRubyに、ということで、ShopifyのYJITのチームがものすごい優秀で、なんかすごいの持ってきてくれて、マジかよっていう感じでした。
作りたいもの「Static Compiler for Ruby」
あとはチャレンジについてちょっとお話しようかなと思います。
ただ、まだ1行もコードを書いてない、思いついただけのレベルなので、それで「V for Vaporware」ですね。存在しないやつです。
作りたいものはこれなんです。「Static Compiler for Ruby」。
最近、スタティックコンパイラはAOT(Ahead of Time)コンパイラとも言って、Rubyのプログラムをマシン語に直接変換するのは、いろいろチャレンジした人もいるんですけれども、正直言うとあんまり性能が出ないんですよね。
ですが、現代においては使える戦略みたいなものがだいぶ増えてきました。
「Abstract Interpretation」であるとか「Profile Guided Type Inference」であるとか「Interactive Annotation」であるとか「Descriptive Type」であるとか、そういうアイディアを使うともうちょっとマシなものが作れるんじゃないかなと思います。
Abstract Interpretation
Abstract Interpretationは抽象解釈というもので、実行をトレースして型情報を収集するタイプのアルゴリズムですね。
今、遠藤さんがすごく頑張って作ってくださってるTypeProfの基礎になっているアルゴリズムです。
ソースコードから型情報みたいなのを収集してきて、それを集めて一種の型データベースのようなものを作る、RBSみたいな感じで表現される型データベースです。
Go言語の新しいバージョンに「Profile Guided Optimization」という機能が入りました。つまり実行時にどんな型で呼ばれたかといった情報を保存しておいて、その情報を次回のコンパイルに利用しようと。
それを最適化だけではなくて型推定に使おうというのがProfile Guided Type Inferenceです。
抽象解釈だけでは全部の型情報推測ができないので、こうやって型情報を集める。
これはJITでやってるのと同じアプローチなんですね。JITは実行時の情報を集めて、それに合わせてコンパイルするわけなので。
そうすると、無駄な型チェックを外すことができるので、より高速にコンパイルすることができる余地があると。
Interactive AnnotationとDescriptive Type
Interactive Annotationはどちらかというとあまりいいアイデアだとは思ってないのですが、どうしても抽象解釈や実行時情報だけでは補いきれない情報が存在するので、本当に分からなかったらコンパイルを諦めて、この行のこの型はこれだと思うんですけど合ってますか? と、コンパイラがポップアップで聞きに来るんですね。
いままでのコンパルとは全く違うアプローチになるわけですけれども、欠点としてはソースコード外の情報になってしまうので、結局ソースコードを見ただけではわからない情報をどこかに書いて、隠されたところに保存されるので、あんまりいいアプローチではないなと。
どうしても分からないときだけ使う、最後の手段ではないかなと思っています。
Descriptive Typeは、型情報というと例えばString型とかInteger型とかGeneric型とか、そういうのを考えるんですが、型情報はもっと多くのものを持つことができるんじゃないかなと思うんです。
例えば「a=[1,2,3]」は配列なんだけれど、要素の方にはIntegerが3つ並んでいます。長さは3です、frozenされています/されていません、みたいな、もっとたくさんの情報を扱うことができると思うんですね。
そうするとこれらの情報を使って、例えばfrozenなオブジェクトが破壊的な操作をするようなメソッドと共に呼ばれると、それはエラーで弾くことができるわけですよね。
計算は難しそうなんだけど、より多くの情報を型にエンコーディングできると思っています。
動的型の言語の方がむしろ勝てるのではないか
そうするとですね、これってすごい型情報が複雑かつ長くなるので、明示的な型宣言のある言語には向かないんですね。
持ちたい情報を全部詰め込むと、型宣言に書けなくなる、書きたくなくなるんですね。
そうすると、暗黙的型、つまりいわゆる動的型というタイプの言語の方が、むしろ将来的には勝てるのではないかと思ってるんです。
Rubyをサブセット化した「スピネル」
さらに言うと、コンパイルによって速度が速くなることを考えて、もしかするとある種のRubyの機能をスピードのためだからとか言いながらサブセット化できるんじゃないかなと思っています。
例えば、いつまでたっても導入できない「frozen string literals」、あるいは一昨年のRubyWorld Conferenceでちょっと紹介したアイディアで、まだ実現していない「static barrier」というアイディアがあるんですけれども、この辺を導入できるのではないかなと思っています。
が、だいぶ課題は多くて、そもそもまだ1行も書いていないのが大きな課題ですが、それ以外にも、型推定は正しいプログラムに対して正しい型が付くことを期待してプログラムを書くのですが、ソフトウェアを開発してるときって大体間違いがあるんですよね。
間違ったソースから間違った型情報を引き出して、間違ったところとマッチさせると大惨事が起きる可能性があるんです。
そういうときにどうやってそのエラーから回復するかはアイディアがまだなくて、ですねこれがつまづく理由になるかなと思います。
もしかすると対話的に間違いを教えてくれる、ただ単にエラーメッセージが出てくるだけじゃなくて、対話的に型をデバッグするある種のデバッガみたいなものがもしかすると必要になるかもしれないなと思いつつ、まだ全然分からないので、今後要検討なことがたくさんあります。
Rubyのようなコンパイル型言語に「Crystal」がありますが、これはちょっとアプローチが違うんです。
Crystalは従来型の静的な型で、型推論できるところはしようという感じで、元々Rubyと互換でCrystalのコンパイラもRubyで最初書いてあったのですが、段々枝分かれして違う言語になっています。
で、それとは違うアプローチで型宣言はないままコンパイル型の言語が作れるんじゃないかなと思ってます。
これを「スピネル」と呼ぼう
相変わらず形から入るタイプなので、この言語に名前をつけました。これを「スピネル」と呼ぼうと思ってます。
スピネルって宝石なんですけども、某漫画のキャラクターに、ルビー・ムーンとスピネル・サンという2人組が出てくるので、ルビーと対になるからスピネルだと、コマンド名は「spin」にしようとかですね、1行も書いてませんが。
もうずいぶん昔から頭の片隅ではこういうのを作りたいと思ってはいたんですけれども、物事をゼロから始めるのは大変なんですよね。
それでほったらかしてたんです。
ただ道具立てとしては抽象解釈の実践としてのTypeProfであるとか、実行時の型情報を集めて最適化したネイティブコードを生成するYJITであるとか、Rubyのパーサはメンテナンスが大変なのですが、共通パーサとしてのYarpであるとか、道具立てがだんだん揃ってきたので、これらの知見とかを流用したり、参考にしたりすると、もしかするとスピネルは単なる夢物語ではないところまでいけるんではないかなと考えています。
ちなみにうちの猫もスピネルですね。
未来へのチャレンジ
過去のRubyKaigiとかRubyWorld Conferenceとかのキーノートで私はいろんなアイディアをぶち上げるんですが、その実現率は7割ぐらいなんですよね。
3割ぐらいは言いっ放しで終わるっていう。
このStatic Ruby Compilerが3割に入るか7割入るかは分からないんですけども、次の30年を考えると僕は80歳を超えてるんですが、いずれにしてもRubyという言語が生き残るためにですね、価値を提供し続けることだけが必要だというふうに思うんですね。
価値だけではなくて夢であるとか、ワクワクする気持ちとかも、その価値の中に含めて提供する必要があると思うんです。
その中にその楽しいRuby、楽しいプログラミング、というのも含まれていると思うんですね。
Rubyがどんどん良くなっていくこと、Rubyと関わっていて、新しい技術を作り出していくところを見る。
そして自分自身も新しい技術を作り出していく、参加していく、っていうこともRubyの楽しさの一環ではないかなというふうに思います。
私たちがですねこのような気持ちを忘れない限り、Rubyはこの先10年、20年、30年生き残り続けて、そのうちRubyは死んだと言われなくなるんじゃないかなと思っています。
というわけで、Rubyの未来、ワクワクすることを待っている、作り出すという決意を新たにしつつ、今日のキーノートを終わります。