Fastブロック

ちょっとPython風味でも浴びようかと思って、ちょろっと書いてみる。
しかし、テキスト処理をCで書いて、30FPSで数百個のオブジェクトが動くような処理をPythonで書いてる僕はどうかしてるな。


ううむ。しかし、あの程度の速度しか出ないのか。もう少しなんとかなると期待してたんだけど。
多分、普段からインタプリタとかGCの悪口ばっかり書いてるからだろうな。無意識のうちに、遅くなるようにコードを書いてしまう。無理矢理メソッドにしたりとか、オブジェクトにしたりとか。
愛があれば、無意識のうちにメソッドの手動インライン展開ぐらいするんだろう。


で、まあ、それはいいか。スクリプト言語に、「機能を限定して、高速化するブロック」とかがあったらどうだろうか、と、ふと思ったのである。Fastブロックとでも呼ぶべきか。


まず、多分、スクリプト言語ボトルネックのうちでもそれなりに大きいのは名前検索だと思う。変数を拾ってくるたびにハッシュテーブルからひいてこないといけない。
たとえば、

x = object()
y = x.nanika.foo()
z = x.nanika.foo()

こんなスクリプトがあると、実際の処理は、

# get がハッシュテーブルから拾ってくる処理

tmp = get( global, "object" )
get( global, "x") = tmp()
tmp = get( global, "x" )
tmp = get( tmp, "nanika" )
tmp = get( tmp, "foo" )
get( global, "y" ) = tmp()
tmp = get( global, "x" )
tmp = get( tmp, "nanika" )
tmp = get( tmp, "foo" )
get( global, "z" ) = tmp()

こんな感じになる。多分。
で、スクリプト言語の柔軟性を考えると、オブジェクトがハッシュテーブルになってるのは仕方無いとしても、上のプログラムは見るからにget呼び過ぎである。パース時に適当に最適化して、

tmp = get( global, "object" )
tmpx = get( global, "x")  # x の値はキャッシュ
tmpx = tmp()
tmp = tmpx
tmpfoo = get( tmp, "foo" )   # fooの値はキャッシュ
get( global, "y" ) = tmpfoo()
get( global, "z" ) = tmpfoo()

このくらいにはしてほしい。


しかし、これが、不可能なのである。スクリプト言語の類いは、オブジェクトの性質が代入するるだけで変わってしまうこともあるし、関数呼び出すだけで、同じ名前でも全然違うオブジェクトになってることもある。Pythonでいうと、getattr、setattrをオーバーライドしてるとか、Rubyでいうと、特異メソッドがどうとか、JavaScriptでいうと、getter、setterだとか。
それをなんとかするには、毎回変数に会うたびにハッシュテーブルから値を拾ってくるしかない。省略してしまうと動作が変わってしまう恐れがある。

だが、そういったちょっと変わった機能というのは、滅多に使われることはない。全く使わなくても良い状況というのは珍しくないだろう。
そこで、Fastブロックなのである。Fastブロックの中では、そういう最適化の邪魔になる機能は使えないが、そのかわり、コンパイラが適当に最適化してくれるかもしれない、としておくのである。適当に値をキャッシュしてくれてるかもしれない。共通部分式が括り出されてるかもしれない。そういう感じ。あと、インライン展開してくれるとか。
まあ、そんな感じ。


あーそうか、関数にFast属性みたいなのを付けれるようにしたらいいのか。Fast属性の関数は再定義できない。Fast属性の関数からは、Fast属性の関数しか呼べない。Fast属性の関数の中では、アクセサは展開されない。そんな感じ。これでいこう。