Javascriptエンジンの上に(ブラウザーまたはスタンドアロンのV8またはSpidermonkeyの上に)Rubyを実装する場合、RubyとJSオブジェクトモデル間の主要なインピーダンスの不一致は何でしょうか?
3 に答える
最も直面しているのは、明らかにECMAScriptがプロトタイプベースであり、Rubyがクラスプラスミックスインベースであるという事実です。また、Rubyでは、カプセル化はオブジェクトで行われ、ECMAScriptではクロージャで行われます。
ただし、Rubyの制御フロー構造は、オブジェクトモデルよりもはるかに大きなハードルになると思います。結局のところ、James CoglanのJS.Class は、基本的にECMAScriptでのRubyのオブジェクトモデルの実装であり、それほど大きくはありません。
ECMAScriptには、その上に独自の制御フロー構造を構築するために必要なツールがありません。GOTO
通常、継続または適切な末尾呼び出しのいずれかが必要です。それらの1つがあれば、例外、ループ、スイッチ、スレッド、Fiber
s、ジェネレーター、コルーチンなど、他のすべてを簡単に実装できます。
しかし、ECMAScriptにはそれらがありません(そして、少なくともの場合には、正当な理由がありますGOTO
)。ECMAScriptが持つ唯一の制御フロー構造は、例外の上に他の構造を構築できるほど強力です。残念ながら、それらはかなり遅いです。(それでも、これらは実装の基盤として使用されています。たとえば、Microsoft Live Labs Voltaコンパイラでは、ECMAScript例外を使用して.NET例外、イテレータ、ジェネレータ、さらにはスレッドを実装していました。)
したがって、基本的には、インタプリタ全体ではないにしても(HotRubyの場合のように)、少なくとも独自のコールスタックを実装したり、グローバルCPS変換などを実行したりすることに固執します。
基本的に、ECMAScript上で実行されるRubyエンジンに必要なのは
- RubySpecの忠実な実装(具体的には、スレッド、ファイバー、
throw
/catch
、例外などの制御フロー構造)、 - パフォーマンスと
- ECMAScriptとの緊密な統合(つまり、2つの言語間でオブジェクトを渡したりメソッドを呼び出したりする機能)。
残念ながら、独自のスタックの管理、CPS変換の実行、例外の上に構築するなどのトリックに頼らなければならない場合、…3つの目標のうち2つしか選択できないことがわかります。
- Rubyにはローカル変数のブロックレベルのスコープがあり、JavaScriptには関数レベルのスコープがあります
- Rubyの継承とミックスインは、JavaScriptのプロトタイプの継承を使用して実装するのはおそらく問題があります。
- メソッド/ラムダ呼び出しに対するRubyのアリティチェックは、JavaScriptのパーミッシブパスよりも厳密です
- Rubyには、真の強制定数があります。JavaScriptはそうではないかもしれません(インタプリタが使用しているバージョンによって異なります)
- クラス変数(ugh)はJaveScriptに同等のものがないため、特別な処理が必要になります
- Rubyのコアにはグリーンスレッドがありますが、JavaScriptにはありません
JavaScriptはチューリング完全であるため、理論的には、他のプログラミング言語を含め、何でも実装できます。実装(JavaScript)とターゲット言語(Ruby)がどれほど異なっていても構いません。RubyとCのような言語間のインピーダンスの不一致は非常に大きく、Ruby、Python、Perl、JavaScript自体がすべてCで実装されています。
JavaScriptでのRubyの実装は、低水準言語での実装よりも桁違いに簡単です。有利なことに、RubyとRubyの標準ライブラリの多くはRuby自体で記述されているため、基本的なインタプリタを使用できるようになると、状況は徐々に悪化するはずです。
JavaScriptで効率的なRubyインタープリターを実装するのは難しいかもしれませんが、それでも可能です。利用可能な優れたオプティマイザーを使用できるように、RubyをJavaScriptに変換することになります。
したがって、RubyとJavaScriptの違いについては考えないでください。Rubyの標準実装を見て、JavaScriptでそれをどのように実装するかを考えてください。