仮想関数を実装しました。
無名関数で実現していたものを言語仕様に盛り込んで、内部で同等のコードに展開すれば簡単にできるかと思ったのですが、内部構造に柔軟性がなかったため予想以上に手間取りました。
使用例
前回、無名関数で書いたものを仮想関数で書き直すと以下のようになります。C#と同じようにvirtualとoverrideを区別します。
struct Test1 { function ctor() { Virt(); } virtual Virt() { printfln("Test1.Virt"); } } struct Test2 : Test1 { override Virt() { printfln("Test2.Virt"); }; } Test1 t1; Test2 t2;
JIT
仮想関数の実装には使っていませんが、実行時にコードを生成すれば色々と応用ができます。メンバ関数へのラッパーを実行時に生成してコールバックとして渡せば、thisポインタをラッパーの中に閉じ込めることができます。
前回、スタックフレームが失われてローカル変数をクロージャに渡せないという問題を取り上げましたが、この方法を使えばクロージャに渡す変数の値をラッパーに封じ込めることができます。試験的に実装したコードは以下のようになります。
// a => b => a * b var currying = function(a) { return new_Delegate(a, function(a, b) { return a * b; }); };
クロージャに渡されるのはコピーされた値なので、クロージャから値を操作しても元の変数には影響しません。変数が共有されるJavaScriptとは挙動が異なり、MLの値束縛に近い挙動です。
この辺りの事情はwikipedia:クロージャで解説されています。