概要
RubyKaigi2015で、John Linさんという方が、ErRubyというErlangVM上で動くRuby実装のLT発表をされてました。興味深い内容でしたのでその紹介をします。
基本情報
ざっくりと言うと、ErlangVM上で動作するErRubyというRuby実装を作った(作っているよ)という内容です。
LTのスライドは以下のリンクからどうぞ。
What I learned by implementing a Ruby VM in Erlang
Githubのリポジトリは以下です。
erruby
目標はRubySpecを通す事だそうです。
アイデア
「ErlangのProcessをRubyのObjectとして扱えば良いんじゃね?」との事。
Erlang Process | Ruby Object | |
---|---|---|
コスト | 低い,max=134,217,727 | 低い,全てがObject |
通信方式 | 非同期通信 | 同期通信 |
example
簡単ですがRubyとErlangの関数呼び出しの比較になります。
Rubyが how_is_sushi?
を同期呼び出ししているのに対して、Erlangは非同期で呼び出しています。
class Alice
def chat_with_bob
res = bob.how_is_sushi? # 1.invokeして結果を待つ 3.結果を受け取る
end
end
class Bob
def how_is_sushi? # 2.Idleで待機、messageを受けたらすしを返す、返したらIdle
"すしわうまい"
end
end
chat_with_bob(Bob) ->
BoB ! {self(), 'how_is_sushi?'}, % 1.BoBにmessageを送信
receive % 2.返信を待つ
{ok, Message} -> Message % 6.返信を受け取る
end.
bob_loop(State) ->
receive
{Sender, 'how_is_sushi?'} -> % 3.messageを受け取る
Sender ! {ok, "すしわうまい"} % 4.返信する
end,
bob_loop(State). %5.待機
Ruby Object in Erlang
Objectに対するメソッド呼び出しは {send, <自身のprocess id>, ...}
のメッセージを送信し、その返却は {method_result, <自分のprocess id>, ...}
のメッセージを送信する事とすると、以下の様になります。
aliceからbobへの呼び出し
alice -> {send, , 'how_is_sushi?', []} -> bob
bobからaliceへの返却
alice <- {method_result, , "すしわうまい"} <- bob
self call method の問題
一見上手くいった様に見えますが、自身に対するメソッド呼び出し bob.sushi_score
の場合に問題となります。
class Alice
def chat_with_bob
res = bob.is_sushi_good?
end
end
class Bob
def is_sushi_good?
sushi_score > 90
end
def sushi_score
9001
end
end
chat_with_bob(Bob) ->
Bob ! {self(), 'is_sushi_good?'}, % 1.Bobにメッセージを送信
receive % 2.Bobからのメッセージを待つ
{ok, Message} -> Message
end.
bob_loop(State) ->
receive
{Sender, 'is_sushi_good?'} -> % 3.メッセージを受ける
(self() ! ({self(), sushi_score}), % 4.自分自身(self)にメッセージを送信
receive {ok, Score} -> % 5.Bobからのメッセージを待ち続ける!!!
Sender ! {ok, Score > 90}
end;
{Sender, sushi_score} ->
Sender ! {ok, 9001}
end,
bob_loop(State).
上記の sushi_score
の様に、自分自身に対してメッセージを送信した場合、 %5
の様に自分自身のメッセージを待つ事になるので、この実装ではダメなわけです。
Ruby Method in Erlang
そこでどうするかというと、「RubyのMethodCallもErlangのProcessにすれば良い」です。
呼び出しイメージ
alice -> (spawn new process) -> {receiver, 'is_sushi_good?', arg, env, sender} -> (spawn new process) -> {receiver, sushi_score, arg, env, sender} -> ...
実装状況
ErRubyの実装状況としては、
- クラス定義
- ブロック・ローカル変数でのメソッドのeval
あたりまでとの事です。多分に実験的ではありますが、実装的にはなかなか面白そうです。興味のある方はコードを追ってみてはいかがでしょうか。
その他の実装に関する情報
ErlPortを使って、ErlangとRubyのブリッジングをしています。
このErlPortをラップしたgemが erlport-ast_mapping となります。
まとめ
今回のRubyKaigiではErlang,Elixir,アクターモデルなど、並行性に関する言及が多くありました。
その中でも特に印象に残ったErRubyについて紹介しました。
スライドにもありますが、まだまだ実験段階のものなので実用には程遠いですが、面白いアイデアのプロダクトなので、今後もwatchしていきたいと思います。