groovy++、来襲
TRANSCRIPT
Groovy++ 、来襲
Date: 2010/12/09
自己紹介名前 : 杉浦孝博twitter: @touchez_du_bois
はじめに本日は、最近気になる OSS の Groovy++ について、・ Groovy++ ってなに?・何ができるの?・ Groovy と何が違うの?とかを語ってみたいと思います。
Groovy ってなに?最初に Groovy とはなにか?Wikipedia 先生に聞いてみたいと思います。
Groovy ってなに?Groovy は JVM 上で動作する言語処理系および言語の名称であり、 Java との直接的な連携を特徴とする。 ( 略 )Groovy は動的な言語であり、 ( 略 )Groovy コードは内部的にはJava バイトコードに変換されて JVM 上で実行される。 ( 略 )
動的な言語Wikipedia 先生によると、コンパイル時に行うことを実行時に行う高級プログラミング言語・コードの追加・オブジェクトや定義の拡張・型システムの変更によるプログラムの拡張
動的な言語のよい点いろいろとありますが・・・・型を書かなくてもよい ( 書く箇所が減る )・コンパイルしないで、すぐ実行できる
動的な言語の残念な点いろいろとありますが・・・・実行速度が遅い・実行してみないとコンパイルエラー的な エラーさえわからない
動的な言語の残念な点動的な言語の残念な点は、 Groovy にもあてはまります。・実行速度が遅い・実行してみないとコンパイルエラー的な エラーさえわからない
Groovy の残念な点実行速度については・・・・ GroovyServ で起動時間は改善できます !!・その他は Java 化で高速に!! ...(^_^;)
Groovy の残念な点コンパイルエラー的なエラーについては・・・・ IDE でどうにかなる?
そこでGroovy++ の登場です。
Groovy++ ってなに?Groovy++ とは、・ Groovy を静的型付けする拡張機能です。
Groovy++ ってなに?つまり、・静的な型付けにより、 Groovy が持つ動的 言語の残念な点をある程度改善します。
Groovy++ ってなに?Groovy++ が提供する機能はそれだけではありません。
Groovy++ ってなに?こんなものも・ Trait・ GrUnit・ Tail Recursion
Groovy++ ってなに?今回はパスします。・ Trait・ GrUnit・ Tail Recursion
さっそく使ってみようまずはプロジェクトのページへhttp://code.google.com/p/groovypptest/
さっそく使ってみようプロジェクトのページです。
さっそく使ってみようgroovypp-0.4.101.zip をダウンロードします。
さっそく使ってみよう展開して、環境変数 GROOVY_HOME とPATH を設定します。・ export GROOVY_HOME=/opt/groovypp-0.4.101・ export PATH=${GROOVY_HOME}/bin:${PATH}
さっそく使ってみようgroovy コマンドでスクリプトを実行します。
$ groovy < スクリプトファイル名 >
さっそく使ってみようこれだけでは、 Groovy を普通に動かすのと変わりません。スクリプトファイルを変更する必要があります。
さっそく使ってみよう通常の Groovy プログラム
package sample
println "Hello, World!"
さっそく使ってみようGroovy++ 化
@Typedpackage sample
println "Hello, World!"
さっそく使ってみよう「基本的に」 Typed アノテーションを付けるだけ。
で、どうなるの?Typed アノテーションを付けることにより、静的な型付がなされ、実行速度がアップします!!
どれくらい速くなるの?サンプルのクイックソート・ Groovy : 284.758 秒
どれくらい速くなるの?サンプルのクイックソート・ Groovy : 284.758 秒・ Groovy++ : 3.387 秒 (※@Typed を付けただけ )
どれくらい速くなるの?サンプルのクイックソート・ Groovy : 284.758 秒・ Groovy++ : 3.387 秒 (※@Typed を付けただけ )・ Java : 2.394 秒
どれくらい速くなるの?
どうなってるの?Groovy のコードからバイトコードに変換されるときに、「錬金術」が発動されます。
どうなってるの?Groovy のコードからバイトコードに変換されるときに、「 AST(Abstract Syntax Tree) 変換」を使って、静的に型解決されたバイトコードを生成します。
どうなってるの?groovyc コマンドで Groovy コードをバイトコードに変換し、 jad で生成されるバイトコードを見てみましょう。
どうなってるの?クイックソートのメインとなるメソッドです。def quicksort(int[] a, int L, int R) { int m = a[(L+R) >> 1] int i=L int j=R while (i<=j) { while (a[i]<m) i++ while (a[j]>m) j-- if (i<=j) { swap(a, i, j) i++ j-- } } if (L<j) quicksort(a,L,j) if (R>i) quicksort(a,i,R)}
どうなってるの?@Typed 付けない場合です。public Object quicksort(int a[], int L, int R) { CallSite acallsite[] = $getCallSiteArray(); Integer m = (Integer)ScriptBytecodeAdapter.castToType(acallsite[19].call(a, acallsite[20].call(acallsite[21].call(DefaultTypeTransformation.box(L), DefaultTypeTransformation.box(R)), $const$3)), $get$$class$java$lang$Integer()); Integer i = (Integer)ScriptBytecodeAdapter.castToType(DefaultTypeTransformation.box(L), $get$$class$java$lang$Integer()); Integer j = (Integer)ScriptBytecodeAdapter.castToType(DefaultTypeTransformation.box(R), $get$$class$java$lang$Integer()); do { if(!ScriptBytecodeAdapter.compareLessThanEqual(i, j)) break; while(ScriptBytecodeAdapter.compareLessThan(acallsite[22].call(a, i), m)) { Integer integer = i; i = ((Integer) (acallsite[23].call(i))); Integer _tmp = integer; } while(ScriptBytecodeAdapter.compareGreaterThan(acallsite[24].call(a, j), m)) { Integer integer1 = j; j = ((Integer) (acallsite[25].call(j))); Integer _tmp1 = integer1; } if(ScriptBytecodeAdapter.compareLessThanEqual(i, j)) { acallsite[26].callCurrent(this, a, i, j); Integer integer2 = i; i = ((Integer) (acallsite[27].call(i))); Integer _tmp2 = integer2; integer2 = j; j = ((Integer) (acallsite[28].call(j))); Integer _tmp3 = integer2; } } while(true); if(ScriptBytecodeAdapter.compareLessThan(DefaultTypeTransformation.box(L), j)) acallsite[29].callCurrent(this, a, DefaultTypeTransformation.box(L), j); if(ScriptBytecodeAdapter.compareGreaterThan(DefaultTypeTransformation.box(R), i)) return acallsite[30].callCurrent(this, a, i, DefaultTypeTransformation.box(R)); else return null; }
どうなってるの?@Typed 付けた場合です。public Object quicksort(int a[], int L, int R) { do { int m = ArraysMethods.getAt(a, L + R >> 1); int i = L; int j = R; do { if(i > j) break; for(; ArraysMethods.getAt(a, i) < m; i++); for(; ArraysMethods.getAt(a, j) > m; j--); if(i <= j) { swap(a, i, j); i++; j--; } } while(true); if(L < j) quicksort(a, L, j); if(R > i) { R = R; L = i; a = a; this = this; } else { return null; } } while(true);}
どうなってるの?静的に解決されたコードが生成され、実行されるので、速くなるのが解っていただけると思います。
明日からGroovy のコードに @Typed を付けまくるぞ!!
でも
そう簡単にはいきません
なぜ?エドワード・エルリックという錬金術師は、第1話「二人の錬金術師」でこう言いました。
なぜ?「つまり錬金術の基本は『等価交換』!!何かを得ようとするなら、それと同等の代償が必要ってことだ」
代償?代償、ってほどでもないのですが、注意点があります。
代償?@Typed を付けても、動かなかったり、動作が変わったりする場合があります。
@Typed を付けられる位置@Typed を付けられる位置は決まっています。・パッケージ・クラス、インタフェース、列挙・コンストラクタ・メソッド
@Typed を付けられる位置以下のコードは、
@Typed
println "Hello, World!"
@Typed を付けられる位置コンパイルエラーになります。org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:C:\Sample\ex01.groovy: 3: unexpected token: println @ line 3, column 1. println "Hello, World!" ^
1 error
@Typed を付けられる位置動かすためには、 package を指定します。
@Typedpackage example
println "Hello, World!"
コンパイル時にエラー間違ったメソッド呼び出しの場合
"Hello, World!".toStrings()
コンパイル時にエラーGroovy は実行時にエラーになります。Caught: groovy.lang.MissingMethodException: No signature of method: java.lang.String.toStrings() is applicable for argument types: () values: []Possible solutions: toString(), toString(), toString(), contains(java.lang.CharSequence), contains(java.lang.String), substring(int)
at example.ex02.run(ex02.groovy:4)
コンパイル時にエラーGroovy++ はバイトコード変換時 ( コンパイル時 ) にエラーになります。org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:C:\Sample\ex02.groovy: 4: Cannot find method String.toStrings() @ line 4, column 17. "Hello, World!".toStrings() ^1 error
実行時に解決するものはGroovy では問題なく動きますが、
package example
String.metaClass.p = { println "${delegate.size()} : ${delegate}"}
"Hello, World!".p()
実行時に解決するものはGroovy++ では
@Typedpackage example
String.metaClass.p = { println "${delegate.size()} : ${delegate}"}
"Hello, World!".p()
実行時に解決するものはコンパイルエラーになります。
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:C:\Sample\ex03.groovy: 5: Cannot find property p of class MetaClass @ line 5, column 18. String.metaClass.p = { ^1 error
実行時に解決するものは解決方法は、 @Typed を付けないか、 @Typed(TypePolicy.MIXED) を付けます。
@Typed(TypePolicy.MIXED)package example
String.metaClass.p = { println "${delegate.size()} : ${delegate}"}
"Hello, World!".p()
実行時に解決するものは指定できる TypePolicy は、以下のとおり・ STATIC(単に「 @Typed 」とした場合と同じ )・ DYNAMIC(@Typed を付けない場合と同じ )・ MIXED( 静的 / 動的を塩梅良くやってくれる )
アクセス修飾子Groovy では private のプロパティ・メソッドもアクセスできます。package example
class Person { private String name private int age public Person(String name, int age) { this.name = name this.age = age } private dump() { println "name = ${name}, age = ${age}" }}def p = new Person("Mike", 25)p.dump()
アクセス修飾子Groovy++ では@Typedpackage example
class Person { private String name private int age public Person(String name, int age) { this.name = name this.age = age } private dump() { println "name = ${name}, age = ${age}" }}def p = new Person("Mike", 25)p.dump()
アクセス修飾子Groovy++ ではエラーになります。
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:C:\Sample\ex04.groovy: 19: Cannot access method Person.dump() @ line 19, column 3. p.dump() ^1 error
クロージャと final 修飾子Groovy ではpackage example
def evenNum(List list) { def x = 0 list.each { int it -> if (it % 2 == 0) { x++ } } return x}println evenNum([1, 2, 3, 4, 5])
クロージャと final 修飾子Groovy では正常に動作します。
$ groovy ex05.groovy2
クロージャと final 修飾子Groovy++ では@Typedpackage example
def evenNum(List list) { def x = 0 list.each { int it -> if (it % 2 == 0) { x++ } } return x}println evenNum([1, 2, 3, 4, 5])
クロージャと final 修飾子Groovy++ ではコンパイルエラーになります。org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:C:\Sample\ex05.groovy: 8: Cannot modify final field example.ex05$evenNum$1.x @ line 8, column 13. x++ ^1 error
クロージャと final 修飾子ロジックを変更するか@Typedpackage example
def evenNum(List list) { return list.findAll({ int it -> it % 2 == 0}).size()}
println evenNum([1, 2, 3, 4, 5])
クロージャと final 修飾子groovy.lang.Reference を使っても解決できます。@Typedpackage example
int evenNum(List list) { Reference x = [0] list.each { int it -> if (it % 2 == 0) { x++ } } return x}println evenNum([1, 2, 3, 4, 5])
整数同士の割り算整数同士の割り算ですが、
package example
println((4 / 2).class)
整数同士の割り算Groovy では、 BigDecimal になります。
$ groovy ex06.groovyclass java.math.BigDecimal
整数同士の割り算Groovy++ では、 int になります。0.4.96 から 0.4.101 のどこかで、 BigDecimal となりました。
$ groovy ex06.groovyclass java.math.BigDecimal
整数同士の割り算次のソースは、
package example
println(4 / 2)println(5 / 2)
整数同士の割り算Groovy
$ groovy ex07.groovy22.5
整数同士の割り算Groovy++
$ groovy ex07.groovy22 2.5
型推論Groovy++ では、静的な型付けのため、型推論も行っています。
型推論例えばこのコード
@Typedpackage example
def x = new Date()println x + 1
型推論groovyc でコンパイルし、 jad でバイトコードから Java のソースに戻すと・・・
型推論となります。
(省略 ) public Object run() { Object x = new Date(); println(DateGroovyMethods.plus(((Date) (x)), 1)); return null; }(省略 )
型推論def ではなく Date で宣言すれば・・・
@Typedpackage example
Date x = new Date()println x + 1
型推論となります。
(省略 ) public Object run() { Date x = new Date(); println(DateGroovyMethods.plus(x, 1)); return null; }(省略 )
他の G*なプロダクトと一緒他の G*なプロダクトと Groovy++ を一緒に使えるのか?
他の G*なプロダクトと一緒Griffon と Groovy++・試していません m(_ _)m
他の G*なプロダクトと一緒Grails と Groovy++・ Grails プラグインが提供されています。
他の G*なプロダクトと一緒Grails と Groovy++・ダウンロードページからプラグインをダウンロードし、 install-plugin コマンドでインストールします。
$ grails install-plugin /path/to/grails-groovy-plus-plus-0.4.101.zip
他の G*なプロダクトと一緒Grails と Groovy++・ Grails 1.3.6 + Groovy++ プラグイン 0.4.101・ generate-all で生成した Controller クラスに@Typed を付けるとどうなるか?・ create-xxx で生成した Domain Class やService クラスに @Typed を付けるとどうなるか?
他の G*なプロダクトと一緒Grails と Groovy++・作成した Controller クラスや Service クラスに、 @Typed(TypePolicy=MIXED) を付けます。・ @Typed だと、 redirect メソッドや render メソッドでコンパイルエラーになります。
他の G*なプロダクトと一緒Grails と Groovy++・ Domain Class の場合、 @Typed(TypePolicy=MIXED) でも、 @Typeでも、 constraints でエラーになります ...orz
まとめ
まとめ・ Groovy++ は、 Groovy を静的に型付する拡張機能です。
まとめ・ Groovy++ は、 Groovy を静的に型付する拡張機能です。・基本的に @Typed を付けるだけです。
まとめ・ Groovy++ は、 Groovy を静的に型付する拡張機能です。・基本的に @Typed を付けるだけです。・でも「錬金術」なので、 Groovy との違いに気をつけてください。
発表は以上です。
質問、意見、ご要望がありますでしょうか?
以上、ご清聴ありがとうございました。