groovy now and future

43
Groovyなう&ふゅーちゃー それからのGroovy GCR 16th NTTソフトウェア上原潤二 2009/1/15

Upload: junji-uehara

Post on 13-Jan-2015

2.986 views

Category:

Technology


9 download

DESCRIPTION

Groovy new feturesCall site optimization,AST Translation,mixin, etc.

TRANSCRIPT

Page 1: Groovy Now And Future

Groovyなう&ふゅーちゃーそれからのGroovy

GCR 16thNTTソフトウェア上原潤二

2009/1/15

Page 2: Groovy Now And Future

Groovyイン・アクション(GinA)• 国内初のGroovy解説書(翻訳)• “バイブル本“• 対応Groovyバージョン

–原書はGroovy 1.0ベース–サンプルコードをGroovy 1.5.4で動作する

ように緻密に修正。–Groovy 1.0より後に実装された機能につい

ては基本的には追記しない。ので本発表ではそこを説明します

Page 3: Groovy Now And Future

Groovy年表2003 2004 2005

2006 2007 200812月▲

1.5.0

2月▲

1.5.4

2月▲1.0

4月▲

1.1b2

12月▲

1.0b8

8月 3月▲

1.0b4JSR化

2月▲

1.0b10JSR EA

7月▲

1.0 JSR-6

12月▲1.5.71.6-rc1

本日の対象

Grails 0.5.6 Grails 1.0 1.1b2

1.1b1

GinA本対象

Page 4: Groovy Now And Future

Groovy 1.1と1.5の関係•1.1b1, 1.1b2, ・・・, 1.1-RC1,

ときて1.5–Java “5”の機能取り込みと、機能が⼤幅アップしたから

–1.1正式版は存在しない。–本資料では、1.1および1.5の新機能を

のマークで表⽰–ちなみに1.6機能は で。

From 1.1・1.5

From 1.6

Page 5: Groovy Now And Future

Groovy 1.1=1.5の主な機能• Java 5対応

– アノテーション利⽤– enum(ただし、インナークラスになるenumは×)– 可変個数引数– static import– Generics– 共変の戻り値

• ⾔語仕様– エルビス演算⼦– for(;;)形式ループ– 名前付き引数で関数呼び出しの括弧省略

• ジョイントコンパイラ• Expando Meta Class (EMC)• 性能向上,bugfix,改良,etc,etc, From 1.1・1.5

Page 6: Groovy Now And Future

Groovy 1.6の主な機能• ⾔語仕様

– マルチ代⼊(多重代⼊)– 分岐しててもreturn省略可– AST変換– Groovyでアノテーション定義

• 動的な振る舞いに関するもの– JavaインスタンスごとのMetaClass– EMC DSL– 実⾏時Mixin

• ライブラリ: Swing Builderの改善• ツール: Grape• 性能向上• bugfix,改良,etc,etc

From 1.6

Page 7: Groovy Now And Future

ベンチマーク

Page 8: Groovy Now And Future

ベンチマーク!•The Computer Language

Benchmarks Game–Aka “shootout”–マイクロベンチマーク

•抜粋して実施

Page 9: Groovy Now And Future

その前に• 速度にこだわるべき?

–マシンも速くなってるし–Groovyであることで遅いなら、

ボトルネックをJavaで書き直せばよいそれはものすごく簡単

• 処理系速度は体感速度に対して⽀配的とは限らない–ライブラリやIOの性能が⽀配的な場合も

• でも–Groovy同⼠なら⾯⽩かろう

Page 10: Groovy Now And Future

Groovy 1.1beta3を1とした速度⽐

Page 11: Groovy Now And Future

Groovy 1.5.6を1とした速度⽐

Page 12: Groovy Now And Future

感想(感覚的なものです)•Groovy 1.6でメソッドコールが爆

速に(理由は後述)•つってもJRubyと同等(かやや上)•JVM上の⾔語の共通の特徴として

–起動は遅いっすよ–メモリは⽐較的⾷うっすよ

Page 13: Groovy Now And Future

From 1.1・1.5

Page 14: Groovy Now And Future

From 1.1・1.5

エルビス演算⼦(Elvis Operator)•三項演算⼦

A ? B : Cは次と等価if (A) { B } else { C }

•エルビス演算⼦A ?: Bは次と等価if (A) { A } else { B }

※GCCの独自拡張に由来

Page 15: Groovy Now And Future

エルビス演算⼦(Elvis Operator)

Page 16: Groovy Now And Future

ジョイントコンパイラ• GroovyとJavaコードが相互依存してい

てもコンパイル可能にclass A {

B b;}

class B extends A {} • 内部では、Groovyクラスのスタブ(メ

ソッド本体を削除したもの)を⽣成してからJavaコンパイラを起動する

• groovycの-jオプションで実⾏From 1.1・1.5

Page 17: Groovy Now And Future

ExpandoMetaClass (EMC)•プロパティにクロージャを代⼊する

とメソッドの様に扱えるString.metaclass.hello = { println “hello”+delegate }“world”.hello() // helloworldが出⼒

•簡便な動的メソッド定義。•prototypeと同様だが、Groovyでは

クラスベースOOPと⼆本⽴て。EMCは後付け。

From 1.1・1.5

Page 18: Groovy Now And Future

From 1.6

Page 19: Groovy Now And Future

Call Siteキャッシュ,Call Site最適化• 性能向上の主因

–「メソッドコールが遅い」←Groovyの遅さは⼤半これで説明。

• 動的メソッド呼び出しに先⽴つメソッド探索をキャッシュ–動的⾔語で効果が⼤–JRubyが先達–アイデア⾃体は古くからある

• JVM上で極めて有効(後述) From 1.6

Page 20: Groovy Now And Future

動的メソッド呼び出し概念フロー

x = new X()x.foo()

呼び出し側クラス

メソッド探索

Class X {

def foo() {

}

GroovyクラスX

Pogo呼び出し

Pogo …Plain Old Groovy Object

Page 21: Groovy Now And Future

動的メソッド呼び出し概念フロー

x = new X()x.foo()

呼び出し側クラス

メソッド探索

Class X {

}

GroovyクラスX

メタクラスのメソッドの呼び出し

‘foo’ = { }

Xのメタクラス

Page 22: Groovy Now And Future

問題はメソッド探索のコスト• 探索時に以下の判定を⾏う必要がある

–Pojo/Pogoのメソッド?–メタクラス定義メソッド?

•クラスごとのメタクラス?•インスタンスごとのメタクラス?

–プロパティ参照か?–コンストラクタ呼び出しか?–インタセプト可能か?–Staticかどうか?

明らかに重い

Page 23: Groovy Now And Future

Call Site Cache (1回⽬)

x = new X()x.foo()

呼び出し側クラス

メソッド探索

Class X {

}

GroovyクラスX

CallSite

‘foo’ = { }

Xのメタクラス

PogoMetaClassSiteのインスタンスを保存

※CallSiteはSoftReferenceで保持されるので

メモリがなくなってきたら解放される

Page 24: Groovy Now And Future

Call Site Cache (2回⽬)

x = new X()x.foo()

呼び出し側クラス

Class X {

}

GroovyクラスX

CallSite

‘foo’ = { }

Xのメタクラス

保存されたPogoMetaClassSiteのインスタンスをcall()

※実際には呼び出しが複数あるので配列CallSiteArrayで保持※意味が動的に変わったらCallSiteのインスタンスを差し替える

(自分で自分を置き換える。コード的にはこれがやや面白い)

Page 25: Groovy Now And Future

Call Site最適化まとめ• (1)メソッド探索コストを2回⽬以降削減• (2)JITによるインライン展開の道を開く

– マシン語レベルでほんとに展開されているか私は確認してません(Open JDKで確認可)がほんとなら⾮常に効果が⾼い(連鎖的展開を導く)

– インライン展開に関してHotSpotは極めて強⼒• アグレッシブにやって状況変わったら

Deoptimization(最適化戻し)• (3)特定のメタメソッドについて、⾃分専⽤

の速いCall Siteを⽣成– DefaultGroovyMethod#additionals参照

Page 26: Groovy Now And Future

Grape:依存クラス⾃動ダウンロード• Maven/RubyGemsみたいなリポジト

リベースモジュール管理–Apache Ivyベース–Groovyレベルで標準基本機能として実現–必要なクラス/Jarを実⾏時にも取ってこれる–依存関係があれば連鎖的にJarを取ってくる–Grails Pluginのような、実⾏時モジュール

機構は含まない• 効⽤: Groovyスクリプト配布が容易に

From 1.6

Page 27: Groovy Now And Future

From 1.6

Grape使い⽅• アノテーション

• メソッド呼び出しGrape.grab(group:'org.jidesoft', module:'jide-

oss', version:'[2.2.0,)')• ʼgrapeʼコマンド

import org.junit.*@Grab(group = 'junit', module='junit', version='*')public class GrapeTestSub {

String testMethod() {Assert.class.name

}}

Page 28: Groovy Now And Future

JavaインスタンスごとのMetaClass• 例:

s = “xxx”;s.metaClass.a = { println "hoge"}s.a()// hogeが出⼒– Groovyならもともと可能– 「JavaクラスごとのMetaClass」は元々あった

• 参考:クラスごとのMetaClassString.metaClass.x={println “hoge” }“abc”.x()// hogeが出⼒

From 1.6

Page 29: Groovy Now And Future

AST変換• AST …抽象構⽂⽊

– コンパイル中にコンパイラ内で作られる中間データ構造

• AST変換– 指定したアノテーションが与える規則に従って、

コンパイル時にASTを変換することで、⾔語機能を加⼯・追加する

– デザインパターン指向プログラミング– コンパイラソースを修正せずに⾔語機能追加。– 定義は結構難しそう(Visitorで)– 利⽤は簡単

From 1.6

Page 30: Groovy Now And Future

AST変換の例プロパティの更新伝播(java.beans. PropertyChangeSupport使⽤)

@Bindable/@Vetoable

newなしで「Integer(5)」と書けばインスタンスが⽣成。(未実装?)

@Newify

packageスコープの指定。フィールドについては動いているようだがクラスについては?

@PackageScope

カテゴリのメソッドをコンパイル時にmixinする

@Category / @Mixinプロパティの怠惰(Lazily)な初期化@Lazy

委譲(delegation)パターンを透過的に実現

@Delegateインスタンス⽣成後の変更を禁⽌@Immutableクラスをシングルトンに変換@Singleton

説明アノテーション

Page 31: Groovy Now And Future

AST変換: @Singleton@Singleton class Foo {def hello() { println "hello" }

}Foo.instance.hello() // シングルトン参照a = new Foo() // newでインスタンス⽣成不可ERROR

java.lang.RuntimeException: Can't instantiate singleton Foo. Use Foo.instance

Page 32: Groovy Now And Future

AST変換: @Immutable@Immutable final class Foo {String x, y

}a = new Foo("a","b")a.x = “hoge” 値の変更ERROR

groovy.lang.ReadOnlyPropertyException: Cannot set readonly property: x

Page 33: Groovy Now And Future

AST変換: @Delegateimport java.util.concurrent.locks.*class LockableMap {@Delegate private Map map = [:]@Delegate private Lock lock = new ReentrantLock ()

}res = new LockableMap()res.lock () Lockとして振舞うtry {res.a = 0 Mapとしても振舞う

} finally {res.unlock ()

} ※MapとLockをimplementsもする

Page 34: Groovy Now And Future

AST変換: @Lazyclass LazyTest {@Lazy List s1 ={println "s1 initializing"; [1,2,3] }();List s2 = {println "s2 initializing"; [4,5,6] }();

}x = new LazyTest()// s2 initializing s1の初期化は遅延されるprintln x.s1 s1への参照で初期化実⾏// s1 initializing// [1, 2, 3]が出⼒されるprintln x.s2// [4, 5, 6]が出⼒される

Page 35: Groovy Now And Future

AST変換: @Category/@Mixininterface Mixed {}

@Category(Mixed) class CatClass {def hello() { println "hello" }

}

@Mixin(CatClass)class MyClass implements Mixed {}

x = new MyClass()x.hello()

※interface Mixedの意義が不明。なんらかの処理上のマーカー?

Page 36: Groovy Now And Future

動的なMixinメソッド呼び出し

String.mixin Dateassert "a".getTime() == 1231768545451

From 1.6

Page 37: Groovy Now And Future

整理:さまざまな機能注⼊の⽅法

クラス/インスタンス

実⾏時クロージャ群EMC DSL

クラスオーバーライドはコンパイル時に⾏われるが、処理内容は実⾏時に決定可

メソッド呼び出しに対応する処理

MOP(invokeMethod,methodMissing)

インスタンス実⾏時メソッド呼び出しの前後の処理

インターセプタ

インスタンス実⾏時クロージャExpando

実⾏時

コンパイル時コンパイル時実⾏時

Groovy処理系のコンパイル時

実⾏時(use⽂実⾏時)コンパイル時コンパイル時

注⼊タイミング

クラスメソッド群継承

クラスメソッド群?Delegateアノテーション

クラスメソッドメソッドを書く

クラスメソッド群Mixinアノテーション

クラスstaticメソッド群Category/use

クラスメソッド群Mixinメソッド呼び出し

クラス(Java)staticメソッド群DefaultGroovyMethods.java(DGM)

クラス/インスタンス

クロージャExpandoMetaClass(EMC)

対象注⼊単位名称

1.11.5

1.6

Page 38: Groovy Now And Future

マルチ代⼊(多重代⼊)def (a, b) = [1,2]

def (int i, String j) = [1, 'Groovy']

def a, b(a, b) = func()

• 要素が余ったら捨て、⾜りなかったらnullで補填

From 1.6

Page 39: Groovy Now And Future

分岐しててもreturn省略可def even(x) {

if (x % 2 == 0) { true } else { false }}assert even(2) == trueassert even(1) == false

• ちなみにwhile⽂の最終評価式は値にはならないようだ

From 1.6

Page 40: Groovy Now And Future

EMC DSL• 逐次プロパティに代⼊するのではなく

⼀気に定義する。String.metaClass.define {foo { s-> println s + delegate }bar { println “hello” }

}“world”.foo(“hai”) // haiworldが出⼒“abc”.bar() // helloが出⼒

From 1.6

※効用: 逐次代入だと、途中で未完成状態のクラスが生じるから?

Page 41: Groovy Now And Future

まとめ

Page 42: Groovy Now And Future

まとめ: Groovyの⽬指すもの• Java 7がしょぼくなった今、Groovyは

⾔語機能拡張のメルティングポット–Java 7のクロージャ(案)は、⼿ひどく複雑

そうだったので、正直ほっとしている。• “Java is COBOL”?そうじゃあない。

“Java is C”なんだ。–ポイントは「住み分け」

• Groovyは、JVM上にクラスをローディングするための別記法。

• 「Java+Groovy」は2つで⼀つの技術

Page 43: Groovy Now And Future

参考文献• http://glaforge.free.fr/weblog/index.php?itemid=241• http://www.nabble.com/DGM-and-GDoc-

to14985262.html#a14985262• http://blog.headius.com/2008/05/power-of-jvm.html• http://glaforge.free.fr/weblog/index.php?itemid=99• http://glaforge.free.fr/weblog/index.php?itemid=256• http://www.infoq.com/jp/articles/groovy-1.5-new‘• http://shootout.alioth.debian.org/• http://d.hatena.ne.jp/masanobuimai/20081224/1230123639• http://docs.codehaus.org/display/GROOVY/Grape• http://docs.codehaus.org/pages/viewrecentblogposts.action?k

ey=GROOVY• http://shemnon.com/speling/2008/04/bindable-observable-

properties.html