MacRuby 0.6 リリース

MacRuby 0.6 がリリースされました。0.5 のリリースから約3ヶ月。活発に開発が進められています。

http://www.macruby.org/blog/2010/04/30/macruby06.html

最近 MacRuby の動向をあまり観察していなかったので、この機に 0.6 での変更点をざっくりまとめてみたいと思います。なお内容はほぼ上のリリースノートと、そこからリンクされている tutorial の内容を抜粋/翻訳したものなので詳細な情報は本家を参照してください

Cocoa 開発がより安定

In this release, we believe that MacRuby is now stable enough to consider using it to develop Cocoa applications.

だそうです。バグをたくさん取ったしアプリケーション開発者のフィードバックを受けて CocoaAPI の全てを利用できるようになったので安心して使っていいですよ、という感じでしょうか。
また XCode での開発プロセスも改善したということで、そのひとつとして「コンパイル」ターゲットにより Ahead of time(AOT)コンパイルすることができるようになり配布するアプリケーションに Rubyスクリプトが含まれないようになるそうです。

標準のデバッガ

macrubyd というコマンドラインツールが追加されました。
break point の設定、ステップ実行、データの表示などの基本的な機能は備えているようで、特に print では任意の式を実行することになるので、monkey patch を当てることができます。
が、プロセスへの attach はまだサポートされていないようです。「まだ作りかけでちゃんとテストしてないからね」ということなので今後に期待しましょう。

どちらかというと macrubyd そのものの登場よりも、デバッガをサポートするためのバックエンドの仕組みのほうが気になります。

The compiler, under debug mode, is now generating special traps inside the code. The debugger connects to these traps and allows not only basic debugging operations but also code evaluation.

ということなので DTrace みたいに生成されるコードに trap を埋め込んでそれを利用するようにしているそうなので、Rubyスクリプトレベルのプロファイラにも流用されるかもしれませんし、動的に monkey patch をあてる機構に使えたりするかもしれません。おもしろそうですね。

また

An interesting feature of the debugger is that it has been abstracted into a simple Objective-C API, of which macrubyd is just one client. In the future we might see other clients.

とも書かれているので、やはり今後この仕組みを利用したツールが登場するでしょう。

Grand Central Dispatch の高レベルな API

GCD はマルチコア向けに並列化をしてくれる Mac OS X 10.6 (Snow Leopard) のフレームワークで、MacRuby 0.5 から利用できるようにサポートされていました。0.6 ではより手軽に利用できるように新しい使い方が追加されたようです。

require "dispatch"

job = Dispatch::Job.new { do_somthing }
job.value

上記のように Dispatch::Job.new にブロックを渡すとその内容が自動的にバックグラウンドで実行されて、Dispatch::Job#value でその結果を受け取ることができるようになっています。new はすぐに処理が返りますが value は結果が得られるまでブロックします。これだとほぼ Thread と同じですね。

これだけだと結局 Dispatch::Job#value で処理を待ってしまうので、以下のようにして終了後の処理を登録することもできます。

require "dispatch"

job = Dispatch::Job.new { do_something }
job.value {|v| p v}  # => job 終了後にブロックが実行されて do_something の結果を p で表示
...                  # => job.value にブロックを渡すとすぐに処理が帰ってくる

まあ、これでは value に渡すブロックの処理を do_something の後に実行するだけでいいのであまり意味がありませんね。しかし Dispatch::Job には複数の処理を追加することができるので、それら全てを待って最後に処理させることができます。並列実行するのですからこれが本来の使い方だと思います。

require "dispatch"

job = Dispatch::Job.new
100.times do |i|
  job.add{ do_something(i) }
end
job.value{|v| p v }

ただし Dispatch::Job#value では最後に登録されたブロックの返り値しか取れません。Dispatch::Job#values で全てのブロックの返り値が配列で受け取れるのですが、values にはブロックを渡して非同期に終了を待つ処理を登録することができません。ここはやや残念ですね。まあでも job.value のブロックの中で job.values を呼べばいいので実用上問題はないと思います。

更に Dispatch::Proxy や Dispatch::Job#synchronize メソッドでデータの排他制御をシンプルに扱えるようになっているようです。詳細な使い方は http://svn.macosforge.org/repository/ruby/MacRuby/trunk/lib/dispatch/README.rdoc にもあります。

基本オブジェクトの改善

0.6 では String, Hash, Regexp などの基本オブジェクトの実装がより CRuby 1.9 との互換性があるように
0.5 まででは String は単に NSMutableString の別名で、Hash も実際は NSMutableDictionary でしたが、それぞれ NSMutableString, NSMutableDictionary を継承したクラスとしてきちんと実装しなおされています。これにより、String はついに Encoding 情報を持つようになりましたし、Hash は 1.9 の実装と同様に順序を保存するようになりました。特に Encoding が扱えるようになったのは大きな互換性の改善だと思います。String のエンコーディングの処理は ICU フレームワークを利用しているそうです。

さらに正規表現も鬼車による実装から ICU フレームワークを利用した実装に置き換えられたそうです。これにより正規表現が Thread safe になったのでより効率的に利用できるそうです。肝心のパフォーマンスはどうなんでしょうかね。

CRuby 用の C 言語の拡張ライブラリをサポート

実験的な対応だそうですが、CRuby に書かれた拡張ライブラリを動かすことができるようにしているそうで、Nokogiri, SQLite3, PostgreSQL などを動かすことができたそうです。これもどうやっているのかが気になりますね。

RubySpec を 85% パス

互換性もよくなってきているようです。Rails 3 も(ちょっと修正が必要みたいですが)動くそうです。

0.7 では VM を変更?

個人的には一番気になったのはここで、0.7 ではマルチコア環境でのパフォーマンスの改善のために新たなコンパイラVM を作るそうです。

Development on the next release, 0.7 just started. In that release, we intend to deliver a next generation compiler and virtual machine that provides very good runtime performance for multicore environments.

0.6 は Cocoa サポートやオブジェクトモデルまわりの改善にかなり注力されていた印象ですが、0.7 ではまた VM まわりに大きく変更がありそうです。特にマルチコア環境でのパフォーマンスのためのサポートを VM レベルでするということで、並列プログラミング愛好家の注目も集めそうです。