You got your Ruby in my CLR!

  • Posted by Nick Sieger

http://blog.nicksieger.com/articles/2006/10/23/rubyconf-your-ruby-in-my-clr


Speaker: John Lam


John LamはAvalonとIndigoとFlickrを使ってフォトフラッシュカードアプリケーションを作りたかったが、実装言語にRubyを選びたくもあった。そのため、途中でRubyCLR間の相互運用層(ブリッジ)を作ることにした。


今やJohnはマイクロソフトに仲間入りし、彼の新しいミッション(より広い視野)はCLR上で動的言語の実装を進めることとなった。

  • 型システムの橋渡し
    • CLRでの動的メソッド。これはリフレクションAPIを単純に呼び出すよりもよい。
             Ruby          |  C               |  CLR
             ============================================
             shadow class  |  dynamic method  |  instance
    • Polymorphic Inline Cache(インラインキャッシュを動的に伸長可能にしたもの)。型はそれほど頻繁に変更されないという仮定にもとづき、異なる呼び出しサイトへのメソッドディスパッチをキャシュする。
    • const_missingとmethod_missingを使ったシャドウクラスとメソッドスタブの作成。
    • メソッド内でのオーバーロード解決(Overload resolution)は新たに追加した。1度だけコストがかかる。例をあげると、System::Collections::ArrayList.new の代用となるコンストラクタなど。
    • 統合はCLRをよりRubyらしく感じさせることによってなされた。
  • 実行
    • 同一性が変更されるもの(プロキシオブジェクト)
             ArrayList.new.as(IEnumerable)
    • あまりRubyらしくないが、同一性が維持されるもの
             IEnumerable.get_enumerator(ArrayList.new)

CLRのようなプラットフォーム上でRubyを統合するためのブリッジ手法には、トレードオフと欠点がある。CLRオブジェクトを作れるようにちょくちょく人工的な型情報を注入する必要がある(たとえば配列だと、Array.of(Int32).new(3) など)。Genericsは邪悪である!シンプルなものはそれほど悪く見えない。List.of(Int32).new とかね。でも、そうしなければならないのは痛い(詳しくはJohnのサイトを見るように)。JohnはCLR言語のためのRubyInline的な実装も作った。(たとえそれが汚くとも)うまいことやるために必要だったのだ。最終的にメソッドオーバーロードには問題がある。とくに等価なRubyの型がないときは、これはinstance_shimに取って代わられる。相互運用層(interop layer)で必要な型のメタデータを混ぜ合わせる、別名メソッド(aliasing meth)の類である。


一方、(ブリッジモードの中でさえ)RubyCLR上での馴染みの開発スタイルをよりよくできるシーンはたくさんある。CLRインターフェイスの実装は、RubyオブジェクトをCLRサイドに渡すために必要な特徴である(たとえば、RubyのArrayにIEnumerableを加えるとか)。(データをマーシャリングする)CLR境界を越える際の性能は、C#の〜100倍程度遅いが、依然として速くもある(3百万 calls/sec)。大きな利点はRubyDSLを使うことによって得られた。これで相互運用層の実装がだいぶ楽になっている。また、RubyCLRは、CRL型のなかにメソッドを混在させることもある。その結果、Rubyでださいと感じるAPIを覆い隠せる。これは最も可能性のある方法でRubyの力を本当に活かせている。


私の収穫は、Johnが意欲的な保守担当者を見つけない限り、RubyCLRプロジェクトがおそらくさらに開発されるようには見えないことである。でもこれは推論にすぎない。Johnに確認したわけではない。型システム間のインピーダンスマッチの問題は動的言語の領域で繰り返されるテーマである。Johnの仕事の価値は、この問題を理解する助けとなったことだ。