Rubinius で、Ruby にインクリメント演算子モドキを実装
今のところはまだ C 言語で書かれている Rubinius VM ですが(将来的には、Squeak Smalltalk の VM と似たような感じで、C 言語に直訳可能な Ruby のサブセットにより書き換えられる予定とか)、すでに Smalltalk ばりの面白い機能をいろいろと備えています。
たとえば、Smalltalk では thisContext という第六の擬変数により実行中のコンテキスト(いうまでもなく、Smalltalk ではこんなものもオブジェクト…)を得ることが可能ですが、Rubinius でも MethodContext.current という式で同じ情報にアクセスできます。
Squeak Smalltalk
thisContext class "=> MethodContext " thisContext method class "=> CompiledMethod "
Rubinius Ruby
this_context = MethodContext.current p this_context.class #=> BlockContext p this_context.class.superclass #=> MethodContext p this_context.method.class #=> CompiledMethod
Matz Ruby(Ruby 1.8)や YARV(Ruby 1.9)でも類似の情報にアクセスすることは可能です。しかし、Smalltalk や Rubinius のような細かなコントロールはできません。
その違いを際だたせる例として、ちかごろ某所でもとりあげられたネタで、C 言語などの var++ のようなインクリメント演算子(仮に #inc )を実装してみるという遊びがあります。マクロのある言語でなら比較的たやすい機能拡張の類ですが、マクロを欠いた言語でも、実行時コンテキストが保持する情報に対する十分なアクセスが許されていれば、実現は可能です。
Squeak Smalltalk 版
Object >> inc | sender varIdx | sender := thisContext sender. varIdx := (sender method at: sender pc - 2) \\ 16 + 1. ^sender tempAt: varIdx put: (sender tempAt: varIdx) + 1
| a | a := 4. a inc. ^a "=> 5 "
Rubinius Ruby 版
class Object def inc sender = MethodContext.current.sender method = sender.method decode = method.decode idx = decode.index(decode.detect{ |inst| inst.ip == sender.ip }) sender.locals[method.bytecodes.decode[idx - 2][1]] += 1 end end a = 4 a.inc p a #=> 5
念のため、#inc が何をしているのかを書くと、まず、#sender で自身(#inc)がコールされた時点の実行コンテキスト(スタックに積まれた一つ前のコンテキスト)をたぐりよせます。次に、そうして得られたコンテキストから、実行中のメソッドのバイトコード列と、実行中のバイトコードの場所(Smalltalk では #pc、Rubinius では #ip )についての情報を得て、#inc をコールする(直前の)バイトコードを特定。そのバイトコードから #inc をコールしたオブジェクトが関連付け(代入)されている一時変数を割り出して、内容をインクリメントする…というカラクリになっています。
インクリメント(や、マクロ)は、そもそも Matz Ruby や YARV において、開発者レベルであえて入れていない(つまり入れようと思えば比較的簡単な)機能だ…ということはありますが、たとえばそれらを欠いていても、エンドユーザーレベルで付加したり試行錯誤ができる柔軟性を言語処理系自身が持っていることは楽しいことだと思います(諸般の事情で楽しく思えない人もいると思いますが… (^_^;))。
Smalltalk のそうした(LISP とはまた違う、見方によっては一歩踏み込んだ)ユーザーへの開放度、つかみどころのなさや柔らかさ、「こんなんでも動くんだ!?」的ないい加減さが好きな私としては、Rubinius にはさらなる動的さやイメージベースなども取り込んで、もっともっと Smalltalk っぽくなっていって欲しいな…と期待しています。