0038 号 巻頭言
初稿:2012-05-22
mruby ヒッチハイクガイド
Rubyist Magazine 第 38 号をお届けする。
今号は、あの mame さんこと遠藤侑介さんをお迎えしての
Rubyist Hotlinks 【第 30 回】 遠藤侑介さん 、
yhara さんによる、南米の写真が盛り沢山の
あなたが南米のRubyカンファレンスに参加するべきn個の理由【後編】、
郡司さんが Ruby 界最大の対立に挑む
map と collect、reduce と inject ―― 名前の違いに見る発想の違い、
おなじみの地域 Ruby 会議レポートは第 4 回を数える
RegionalRubyKaigi レポート (28) 関西 Ruby 会議 04、
さらに書籍紹介『―Ruby on Rails 3 で作る― jpmobile によるモバイルサイト構築』に加えて
ワークスコーポレーション様ご提供の
0038 号 読者プレゼント
となっている。
今回は (今回も) 時間がないので、
最近ひそかにリリースされつつある (正式リリースではないそうなのであいまいな表現にしてみるが) mruby のコードを読解するためのメモをそのまま流用したい。
Ruby 処理系のコードの読み方と言えば、青木峰郎さんの名著、Ruby Hacking Guide こと『Ruby ソースコード完全解説』があるので、それに倣って書いてみる。ただし、言うまでもないが、全部書くのは紙面も時間も私自身のコード読解力もないため、第 2 章「オブジェクト」の前半の部分に相当するくらいである。興味のある方は、以下のページも合わせて読んでみるとよいだろう。
また、書く内容も「解説」というより「鑑賞」に近い。むしろガイドブック片手に眺めるくらいの気持ちが似合っている。そんなわけで「mruby ハッキングガイド」などとは名乗らず、このタイトルにしてみた。別に人類や Rubyist が滅びるわけではない。
なお、以下ではいわゆる MRI というか、普通の CRuby 処理系のソースコードを ruby と呼び、mruby と区別する。
値とオブジェクト
それではさっそく RHG を片手に mruby を読んでみよう。
ruby の値は VALUE という型であり、実際にはこれを即値として扱うか、オブジェクトを表す構造体へのポインタとして扱っていた。
(include/ruby/ruby.h)
一方、mruby のそれは大きく異なる。
(include/mruby.h)
VALUE はなくなり、代わりに用意されているのがこの mrb_value だ。
float と void * と int とシンボルとを union でまとめている。
これはつまり、ruby ではトリッキーに埋め込まれた一部の即値以外は VALUE のポインタの先を見て値を取り出すようになっていたのが、mruby では mrb_value のみで素直に値を表せるようになった、ということだ。比較的大きな変更ではないだろうか。特に浮動小数点演算の影響が大きそうだ。……と思ったが、よくよく考えてみると変わったのは浮動小数点数くらいのような気もする。そこまで大きな変更ではないかもしれない。
もちろん、union だけではそれが整数なのか小数なのか、
それとも全く別のオブジェクト(へのポインタ)なのか分からない。ruby では
ポインタの先にある値で区別していたが、mruby でそれをしてしまうと
値を持っている意味がなくなる。そのために追加されたのが mrb_vtype だろう。
mrb_vtype の定義は以下のようになる。
(include/mruby.h)
この mrb_vtype により、例えば float についても mrb_value のみで値が取得できるようになっている。
なお、mrb_float が何かは mrbconf.h で定義できるようになっている。
(include/mrbconf.h)
通常は double だが、MRB_USE_FLOAT を #define すれば float になる。
これは省メモリ環境でも動作させるための配慮だと思われる。
一方、mrb_int と mrb_sym は決め打ちになっている。
(include/mrbconf.h)
概ね予想通りの定義ではないだろうか。
オブジェクト構造体
引き続き RHG に従って mruby を読んでいこう。
VALUE が mrb_value に変わったところから、オブジェクト構造体も気になる。
こちらはどうなっているだろうか。
ruby の場合、オブジェクト構造体は include/ruby/ruby.h にあったが、mruby では各ヘッダファイルに分かれている。
(include/mruby/object.h)
ぱっと見たところでは、こちらは ruby のそれとあまり変わっていない。むしろだいぶシンプルになった感覚がある。少し安心する。
MRUBY_OBJECT_HEADER は気になるが、きっと ruby での RBasic のような、
各オブジェクトに共通する要素をまとめたものだろう、と想像はつく。
中身は以下のようになっている。
(include/mruby/object.h)
c はそのオブジェクトのクラスだろう。RHG にもある通り、mrb_vtype だけでは
すべてのクラスが表現できないため、別途 RClass 型の変数 c が使われている。
このクラスと flags は ruby とも共通するが、それ以外にも情報が増えている。
何となく GC に関連するような気がするが、ここでは深入りしない。
なお、mruby での RBasic は以下のようになっている。
(include/mruby/object.h)
推測通りだっただろうか。
基本的なオブジェクト
ruby ではいくつかのオブジェクトはポインタではなく、値が埋め込まれていた。
(ruby/ruby.h)
この辺り、mruby ではどうなっているだろうか。
(include/mruby.h)
なんと static インライン関数になっている。
C のインライン関数は C99 で標準に取り込まれた、らしい。mruby はその特徴として、
C99 準拠がうたわれている。そのため、C99 の機能は遠慮なく使っているのだろう。
もっとも、C99 の inline はヒントであって最適化やそのほかのコンパイラの都合によりインライン化されないこともあり……という話はよく知らないので深入りしないでおく。
mruby に戻る。mrb_false_value() は見ての通り、型情報として MRB_TT_FALSE を持ち、
値としては 1 を持つ mrb_value を返している。
MRB_TT_FLASE は Ruby の false だけではない。nil の時にも使われる。mrb_nil_value() はこうだ。
(include/mruby.h)
こちらはポインタとして 0 を与えている。なぜ v.value.i ではないのかは分からなかった。
ちなみに nil かどうかを調べるマクロは以下のようになっている。
(include/mruby.h)
同様に、真偽値を返す mrb_test() はこうなる。
(include/mruby.h)
つまり、MRB_TT_FALSE は false かどうかではなく、Ruby の「偽」の値を表すものだと考えればよいようだ。
ついでなので、true と undef を返す mrb_true_value() と mrb_undef_value() も紹介しておく。
(include/mruby.h)
同じような形になっている。
メソッド
続いてクラスを見てみよう。mruby のクラスの構造体も、ruby 同様 RClass になっている。
(include/mruby/class.h)
ruby そっくりだ。iv がインスタンス変数、mt がメソッドテーブルだと推測できる。
メソッド探索は mrb_method_search() になる。
これを見る限り、どうやら mrb_method_search_vm が本体のようだ。こちらはこうなっている。
kh_ で始まるものはハッシュの操作になっている。中身は include/khash.h に詳しいが、ここでは触れないでおく。
OOPL のメソッド探索の挙動に親しみがあるのなら、おおまかな挙動もだいたい推測がつくかもしれない。
各クラスが持つメソッドテーブル c->mt に対し、
メソッドの ID である mid があればその値 (m) を返し、なければクラスをさかのぼり、
見つからなければ 0 を返す。ちょっと kh_ 関連のクセはあるが、
やっていることはふつうのメソッド探索である。
なお、この第一引数である mrb_state というのは、mruby のインタプリタの本体というか、
その状態を持っている値である。定義は長いが以下のようになっている。
(include/mruby.h)
長いと書いたが本当に長い。というか object_class や class_class など、
普通の意味では state ではないものも含んでる。
いずれにしても、確かにこれくらいあれば、ruby の実行状態を表すために必要な情報は全て含まれていそうだ。
以下、mrb_state の解説をするか、変数周りについての解説をするか、というところだが、
すでに長くなってしまったので(そして私自身もまだ理解できていないので)今回はここまでにする。
なんとなく、mruby の雰囲気はつかめただろうか。
CRuby 1.9 のソースに比べれば、全体的にシンプルになっているような気がする。Ruby 処理系の実装に興味があるのなら、CRuby (や JRuby、rubinious) もさることながら、mruby のソースを読んでみるのもおすすめしたい。
(るびま編集長 高橋征義)