どう書く.org課題の「inline/embeded bytecode assembly」をやってみました。
手っ取り早くjavassistで。
@Grab('javassist:javassist:3.8.0.GA') import javassist.*; ClassPool pool = ClassPool.getDefault(); CtClass cc = pool.makeClass("DuffsDevice"); CtMethod m = CtNewMethod.make(""" public static void copy(byte[] to, byte[] from) { int count = from.length; int i = 0; switch (count % 8) { case 7: to[i] = from[i++]; case 6: to[i] = from[i++]; case 5: to[i] = from[i++]; case 4: to[i] = from[i++]; case 3: to[i] = from[i++]; case 2: to[i] = from[i++]; case 1: to[i] = from[i++]; case 0:; } while (i < count) { to[i] = from[i++]; to[i] = from[i++]; to[i] = from[i++]; to[i] = from[i++]; to[i] = from[i++]; to[i] = from[i++]; to[i] = from[i++]; to[i] = from[i++]; } } }""", cc); cc.addMethod(m); def dev = cc.toClass().newInstance() def to = new byte[3] dev.copy(to, [1,2,3] as byte[]) to.each { println it }
対象コードはJava版のを使わせていただきました。
動的型付けではない、静的型付けの高速なJavaのセマンティクスで動くコードをGroovyコードに追加できるということで、ある種の高速化テクニックになるかもしれません。もちろん、そんなことするぐらいならあらかじめjavacしとけという話にはなるんですが、何らかの理由でjavacを使えないという状況、例えばGAE/J上のような環境で、オンザフライJavaコンパイルして動くようなことができるかもね。javaassistがGAE/J上で動作するかは不明ですが。
あと、ASTBuilder.fromCode()で用いられている「クロージャを文字列に変換する」技術を使えば、GroovyのクロージャをJavaのブロックと解釈させるようなこともできるかもしれませんね。
てなことを、実は昔も妄想で書いてます。
ちなみに、この種の感想(部分的に静的タイピングでいいから高速化したい!)は誰もが思うことのようで、過去に@Typedアノテーションみたいなかたちで提案されたりしています。しかし、Groovyに取り入れられていないのは、意図的ではあるようですね(少なくとも気づいていないという訳ではない)。