• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
 

Introduce Groovy 2.3 trait

on

  • 211 views

Trait is new feature which is introduced to Groovy 2.3.

Trait is new feature which is introduced to Groovy 2.3.
This presentation explain short summary of trait and how to use it, what purpose it suit for.

Statistics

Views

Total Views
211
Views on SlideShare
155
Embed Views
56

Actions

Likes
0
Downloads
0
Comments
0

2 Embeds 56

http://orangeclover.hatenablog.com 39
http://uehaj.hatenablog.com 17

Accessibility

Categories

Upload Details

Uploaded via SlideShare as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Introduce Groovy 2.3 trait Introduce Groovy 2.3 trait Presentation Transcript

    • GroovyのTraitを使い倒す 2014/06/20 JGGUG  G*Workshop NTTソフトウェア株式会社上原潤⼆二 14年6月21日土曜日
    • Copyright (C) 2014 NTT Software Corp. ⾃自⼰己紹介 • 上原潤⼆二(@uehaj) • NTTソフトウェア(株)Grails推進室 • JGGUG(⽇日本Grails/Groovyユーザグループ)運営委員 • 書籍執筆:プログラミングGROOVY(技術評論論 社),Grails徹底⼊入⾨門(翔泳社) • ブログ「Grな⽇日々」 • GroovyServ,  LispBuilder,  GVM(JVM   written  in  Groovy)開発者 14年6月21日土曜日
    • Copyright (C) 2014 NTT Software Corp. Trait • 「特徴」の意 • Self,  Squeak  Smalltalk,  PHP,  Rust,   D,Scala...などにもTraitという名称の⾔言 語機能がある。C++にはTraitsという技 法がある。それぞれでの意味は、かなり/ 全然違う • Groovy  2.3で新規(⽬目⽟玉?)機能として導⼊入 • GroovyのtraitはScalaのに⽐比較的近い 14年6月21日土曜日
    • Copyright (C) 2014 NTT Software Corp. Groovyのtrait • ×多重継承が可能なクラス • 直接インスタンス化できない •  oo実装を持てるインターフェース • 状態も持てる(Java8のDefault  Methodとは違う) • 多重継承に付随する「ダイヤモンド継承」問題を解決 • インスタンス変数→変数名リネーム • メソッド衝突→線形化順序(後述) 14年6月21日土曜日
    • Copyright (C) 2014 NTT Software Corp. traitの定義と使⽤用 • trait T { ... } • Traitは直接インスタンス化できない • def x = new T() // × • Traitを静的に実装するクラスをインスタンス化 class C implements T {} // like interface def y = new C() // OK • Traitを実装するプロキシを動的に⽣生成 def z = new String() as T def z2 = new String().withTraits(T1,T2) assert ! (z instanceof String) assert z instanceof T 14年6月21日土曜日
    • Copyright (C) 2014 NTT Software Corp. traitの定義と使⽤用 • trait T { ... } • Traitは直接インスタンス化できない • def x = new T() // × • Traitを静的に実装するクラスをインスタンス化 class C implements T {} // like interface def y = new C() // OK • Traitを実装するプロキシを動的に⽣生成 def z = new String() as T def z2 = new String().withTraits(T1,T2) assert ! (z instanceof String) assert z instanceof T 「as  Interface」でプロキシ⽣生成す るのはGroovyにもとからある機能 14年6月21日土曜日
    • Copyright (C) 2014 NTT Software Corp. サンプルコード trait  Helloable  {//  helloを表示する能力    void  hello()  {        println  "hello  "+this.toString()    }    void  hello2()  {        println  "hello  "+proxyTarget.toString()    } } class  World  implements  Helloable  {    String  toString(){  "world"} } x  =  new  World() x.hello()    //  ==>  hello  world y  =  "abc"  as  Helloable y.hello()    //  ==>  hello  String1_groovyProxy@5560a7b1 z  =  "def"  as  Helloable z.hello2()  //  ==>  hello  def Traitを静的に実装するクラ スをインスタンス化 Traitを実装するプロキシを動的に⽣生成。インスタンスへの動的メソッド追加ぽいことが できる。状態も持てる。ただしStringそのものではなくプロキシ経由。 14年6月21日土曜日
    • Copyright (C) 2014 NTT Software Corp. proxyTarget • 動的に⽣生成されたTraitを実装するプロキシのみが保持す るプロパティ • プロキシしている元のオブジェクトを指す • def x = new String() def y = x.withTraits(T1,T2) assert x == y.proxyTarget assert y.proxyTarget instanceof String http://jira.codehaus.org/browse/GROOVY-6692 14年6月21日土曜日
    • Copyright (C) 2014 NTT Software Corp. traitのsuper • Traitのメソッド中において、superのクラスは? • traitの継承階層は⼀一意に静的に定まるツリー ではない。superのクラスはTrait定義時には わからない。   • traitsを(静的/動的)にimplementsする箇 所において、traitの指定順序により異異なり得 る線形化順序がsuperのクラスを定める • 呼び出したいTraitが確定しているなら、不不定の superに頼らず<Trait名>.super 14年6月21日土曜日
    • Copyright (C) 2014 NTT Software Corp. ちょっとややこしいコード trait  A  {  String  whoami(){"A  -­‐>"+super.whoami()}  } trait  B1  extends  A  {  String  whoami(){"B1  -­‐>"+super.whoami()}  }; trait  B2  extends  A  {  String  whoami(){"B2  -­‐>"+super.whoami()}  }; trait  C1  extends  B1  {  String  whoami(){"C1  -­‐>"+super.whoami()}  }; trait  C2  extends  B1  {  String  whoami(){"C2  -­‐>"+super.whoami()}  }; trait  C3  extends  B2  {  String  whoami(){"C3  -­‐>"+super.whoami()}  }; trait  C4  extends  B2  {  String  whoami(){"C4  -­‐>"+super.whoami()}  }; class  D  implements  C4,C3,A,C2,C1  {  String  whoami(){"D"}  } class  E  extends  D  implements  C1,C2,C3,C4  {} m  =  new  E() println  m.whoami() //  C4  -­‐>B2  -­‐>A  -­‐>C3  -­‐>C2  -­‐>B1  -­‐>C1  -­‐>D 14年6月21日土曜日
    • Copyright (C) 2014 NTT Software Corp. 継承階層の線形化順序 (メソッド探索索したり、superを辿る順序) extends (implements) extends <<trait>> C1 <<trait>> C2 <<trait>> C3 <<trait>> C4 <<trait>> B1 <<trait>> B2 <<trait>> A <<Class>> D 14年6月21日土曜日
    • Copyright (C) 2014 NTT Software Corp. 継承階層の線形化順序 (メソッド探索索したり、superを辿る順序) extends (implements) extends <<trait>> C1 <<trait>> C2 <<trait>> C3 <<trait>> C4 <<trait>> B1 <<trait>> B2 <<trait>> A <<Class>> D <<Class>> E クラスDにtrait C1∼C4から機 能注入したものをEとする class E extends D implements C1,C2,C3,C4 14年6月21日土曜日
    • Copyright (C) 2014 NTT Software Corp. 継承階層の線形化順序 (メソッド探索索したり、superを辿る順序) extends (implements) extends <<trait>> C1 <<trait>> C2 <<trait>> C3 <<trait>> C4 <<trait>> B1 <<trait>> B2 <<trait>> A <<Class>> D <<Class>> E クラスDにtrait C1∼C4から機 能注入したものをEとする class E extends D implements C1,C2,C3,C4 Eから始めて、 右側優先、下か ら上への深さ優 先探索 14年6月21日土曜日
    • Copyright (C) 2014 NTT Software Corp. 継承階層の線形化順序 (メソッド探索索したり、superを辿る順序) extends (implements) extends <<trait>> C1 <<trait>> C2 <<trait>> C3 <<trait>> C4 <<trait>> B1 <<trait>> B2 <<trait>> A <<Class>> D <<Class>> E クラスDにtrait C1∼C4から機 能注入したものをEとする class E extends D implements C1,C2,C3,C4 Eから始めて、 右側優先、下か ら上への深さ優 先探索 Scalaのと は異なる 14年6月21日土曜日
    • Copyright (C) 2014 NTT Software Corp. 継承階層の線形化順序 (メソッド探索索したり、superを辿る順序) extends (implements) extends <<trait>> C1 <<trait>> C2 <<trait>> C3 <<trait>> C4 <<trait>> B1 <<trait>> B2 <<trait>> A ① <<Class>> D <<Class>> E クラスDにtrait C1∼C4から機 能注入したものをEとする class E extends D implements C1,C2,C3,C4 Eから始めて、 右側優先、下か ら上への深さ優 先探索 Scalaのと は異なる 14年6月21日土曜日
    • Copyright (C) 2014 NTT Software Corp. 継承階層の線形化順序 (メソッド探索索したり、superを辿る順序) extends (implements) extends <<trait>> C1 <<trait>> C2 <<trait>> C3 <<trait>> C4 <<trait>> B1 <<trait>> B2 ② <<trait>> A ① <<Class>> D <<Class>> E クラスDにtrait C1∼C4から機 能注入したものをEとする class E extends D implements C1,C2,C3,C4 Eから始めて、 右側優先、下か ら上への深さ優 先探索 Scalaのと は異なる 14年6月21日土曜日
    • Copyright (C) 2014 NTT Software Corp. 継承階層の線形化順序 (メソッド探索索したり、superを辿る順序) extends (implements) extends <<trait>> C1 <<trait>> C2 <<trait>> C3 <<trait>> C4 <<trait>> B1 <<trait>> B2 ② <<trait>> A ① <<Class>> D ③ <<Class>> E クラスDにtrait C1∼C4から機 能注入したものをEとする class E extends D implements C1,C2,C3,C4 Eから始めて、 右側優先、下か ら上への深さ優 先探索 Scalaのと は異なる 14年6月21日土曜日
    • Copyright (C) 2014 NTT Software Corp. 継承階層の線形化順序 (メソッド探索索したり、superを辿る順序) extends (implements) extends <<trait>> C1 <<trait>> C2 <<trait>> C3 <<trait>> C4 <<trait>> B1 <<trait>> B2 ② <<trait>> A ①④ <<Class>> D ③ <<Class>> E クラスDにtrait C1∼C4から機 能注入したものをEとする class E extends D implements C1,C2,C3,C4 Eから始めて、 右側優先、下か ら上への深さ優 先探索 Scalaのと は異なる 14年6月21日土曜日
    • Copyright (C) 2014 NTT Software Corp. 継承階層の線形化順序 (メソッド探索索したり、superを辿る順序) extends (implements) extends <<trait>> C1 <<trait>> C2 <<trait>> C3 <<trait>> C4 <<trait>> B1 <<trait>> B2 ② <<trait>> A ①⑤ ④ <<Class>> D ③ <<Class>> E クラスDにtrait C1∼C4から機 能注入したものをEとする class E extends D implements C1,C2,C3,C4 Eから始めて、 右側優先、下か ら上への深さ優 先探索 Scalaのと は異なる 14年6月21日土曜日
    • Copyright (C) 2014 NTT Software Corp. 継承階層の線形化順序 (メソッド探索索したり、superを辿る順序) extends (implements) extends <<trait>> C1 <<trait>> C2 <<trait>> C3 <<trait>> C4 <<trait>> B1 <<trait>> B2 ②⑥ <<trait>> A ①⑤ ④ <<Class>> D ③ <<Class>> E クラスDにtrait C1∼C4から機 能注入したものをEとする class E extends D implements C1,C2,C3,C4 Eから始めて、 右側優先、下か ら上への深さ優 先探索 Scalaのと は異なる 14年6月21日土曜日
    • Copyright (C) 2014 NTT Software Corp. 継承階層の線形化順序 (メソッド探索索したり、superを辿る順序) extends (implements) extends <<trait>> C1 <<trait>> C2 <<trait>> C3 <<trait>> C4⑦ <<trait>> B1 <<trait>> B2 ②⑥ <<trait>> A ①⑤ ④ <<Class>> D ③ <<Class>> E クラスDにtrait C1∼C4から機 能注入したものをEとする class E extends D implements C1,C2,C3,C4 Eから始めて、 右側優先、下か ら上への深さ優 先探索 Scalaのと は異なる 14年6月21日土曜日
    • Copyright (C) 2014 NTT Software Corp. 継承階層の線形化順序 (メソッド探索索したり、superを辿る順序) extends (implements) extends <<trait>> C1 <<trait>> C2 <<trait>> C3 <<trait>> C4⑦ <<trait>> B1 <<trait>> B2 ②⑥ <<trait>> A ①⑤ ④ <<Class>> D ⑧ ③ <<Class>> E クラスDにtrait C1∼C4から機 能注入したものをEとする class E extends D implements C1,C2,C3,C4 Eから始めて、 右側優先、下か ら上への深さ優 先探索 Scalaのと は異なる 14年6月21日土曜日
    • Copyright (C) 2014 NTT Software Corp. 継承階層の線形化順序 (メソッド探索索したり、superを辿る順序) extends (implements) extends <<trait>> C1 <<trait>> C2 <<trait>> C3 <<trait>> C4⑦ <<trait>> B1 <<trait>> B2 ②⑥ <<trait>> A ①⑤ ④ <<Class>> D ⑧ ③ <<Class>> E クラスDにtrait C1∼C4から機 能注入したものをEとする class E extends D implements C1,C2,C3,C4 Dがどんな順序でどの traitをimplementsして いるかは、Eからの superリンクの形成には 無関係 Eから始めて、 右側優先、下か ら上への深さ優 先探索 Scalaのと は異なる 14年6月21日土曜日
    • Copyright (C) 2014 NTT Software Corp. コード再掲 trait  A  {  String  whoami(){"A  -­‐>"+super.whoami()}  } trait  B1  extends  A  {  String  whoami(){"B1  -­‐>"+super.whoami()}  }; trait  B2  extends  A  {  String  whoami(){"B2  -­‐>"+super.whoami()}  }; trait  C1  extends  B1  {  String  whoami(){"C1  -­‐>"+super.whoami()}  }; trait  C2  extends  B1  {  String  whoami(){"C2  -­‐>"+super.whoami()}  }; trait  C3  extends  B2  {  String  whoami(){"C3  -­‐>"+super.whoami()}  }; trait  C4  extends  B2  {  String  whoami(){"C4  -­‐>"+super.whoami()}  }; class  D  implements  C4,C3,A,C2,C1  {  String  whoami(){"D"}  } class  E  extends  D  implements  C1,C2,C3,C4  {} m  =  new  E() println  m.whoami() //  C4  -­‐>B2  -­‐>A  -­‐>C3  -­‐>C2  -­‐>B1  -­‐>C1  -­‐>D ここが重要 Dでimplementsするtraitsの順序や有無 はEからのsuperリンクの形成に無関係 14年6月21日土曜日
    • Copyright (C) 2014 NTT Software Corp. 線形化された継承階層(1) class  E  extends  D  implements   C1,C2,C3,C4  {} <<trait>> C1 ⑦ <<trait>> B2 ② <<trait>> B1 ⑥ <<trait>> C4 ① <<trait>> C2 ⑤ <<trait>> C3 ④ <<Class>> E <<Class>> D ⑧ <<trait>> A ③ trait勢はClass継承の 親との間に挿入される (β版での @ForceOverride指定 の動作) • 右のように単⼀一継 承しているかのよ うにsuperが動作 • クラスDがsuper リンクの終端点と して機能 14年6月21日土曜日
    • Copyright (C) 2014 NTT Software Corp. 線形化された継承階層(2) class  E  implements  C1,C2,C3,C4  {} <<trait>> C1 ⑦ <<trait>> B2 ② <<trait>> B1 ⑥ <<trait>> C4 ① <<trait>> C2 ⑤ <<trait>> C3 ④ <<Class>> E Object(?) <<trait>> A ③ • Dをextendsせず、trait(例例えば C1)を終端点としても良良いが、 • 線形化順序上、C1が常に末端 になるようにプログラマが保証 する必要がある。 • C1ではsuper.whoami()が失 敗 14年6月21日土曜日
    • Copyright (C) 2014 NTT Software Corp. Stackable  Trait • Traitの指定順序が異異なると線形化順序が 異異なることを利利⽤用しメソッドの適⽤用順序 を変更更 • 継承階層を、あと付けで組み替える • 組み合わせ可能なデコレータ 14年6月21日土曜日
    • Copyright (C) 2014 NTT Software Corp. コード例例  Wikiエンジン(1) trait  Bold  {    String  convert(String  s)  {        super.convert(s).replaceAll(/**([^*]*)**/,  '<b>$1</b>')    } } trait  Heading  {        String  convert(String  s)  {                super.convert(s).replaceAll(/(?m)^(#+)  ?(.*)$/)  {  g0,  g1,  g2-­‐>                        "<h"+g1.size()+">"+g2+"</h"+g1.size()+">"                }        } } trait  UL  {        String  convert(String  s)  {                super.convert(s).replaceAll(/(?m)(^s*[^*]*n)(s**)/)  {  g0,  g1,  g2-­‐>                        g1+"<ul>n"+g2                }.replaceAll(/(?m)(^s**.*n)(s*[^*]*n)/)  {  g0,  g1,  g2  -­‐>                        g1+"</ul>n"+g2                }.replaceAll(/(?m)^s**s*(.*)$/,  "<li>$1</li>")        } } class  HtmlConverter  {        String  convert(String  s)  {                "<html>"+s+"n</html>n"        } } 14年6月21日土曜日
    • Copyright (C) 2014 NTT Software Corp. コード例例  Wikiエンジン(2) class  WikiEngine1  extends  HtmlConverter  implements  Bold,  Heading,  UL  {} class  WikiEngine2  extends  HtmlConverter  implements  UL,  Bold,  Heading  {} println  new  WikiEngine1().convert(text) println  new  WikiEngine2().convert(text) println  new  HtmlConverter().withTraits(Bold,  Heading,  UL).convert(text) println  new  HtmlConverter().withTraits(UL,  Bold,  Heading).convert(text) ##this  is  Heading1 #this  is  Heading2 This  is  sample  document  for  wiki   engine. If  you  wan  to  **emphasize**,  use   **This**  markup. #This  is  heading3 This  is  sample  document  for  wiki   engine. *  list1 *  list2 *  list3 This  is  end. **hoge** <html> <h2>this  is  Heading1</h2> <h1>this  is  Heading2</h1> This  is  sample  document  for  wiki  engine. If  you  wan  to  <b>emphasize</b>,  use   <b>This</b>  markup. <h1>This  is  heading3</h1> This  is  sample  document  for  wiki  engine. <ul> <li>list1</li> <li>list2</li> <li>list3</li> </ul> This  is  end. <b>hoge</b> </html> <ul> <li>*hoge**</li> </ul> 14年6月21日土曜日
    • Copyright (C) 2014 NTT Software Corp. まとめ • Groovyのtraitはmixinに近い • ⾃自⾝身のデータ構造とメソッド群によって独⽴立立して機能実現。しか る後にその機能が欲しいクラスに注⼊入する。 • 単⼀一継承じゃだめなんですかオブジェクトコンポジションじゃ… • なくても死なない • しかし、クラス階層(分類の階層、代⼊入可能性の制約)と機能実装 の階層は本来独⽴立立。機能合成の階層構造が単⼀一継承のツリーであ る必然性はない。 • (例例)  read  from  file  +  write  to  file  =>  read  write  file • GroovyのライブラリはJavaベースなのでTrait使ってない。 使いどころはアプリコード。DI的に使ったり?  DCI? • Scalaでの利利⽤用が参考になるかも。 14年6月21日土曜日
    • Copyright (C) 2014 NTT Software Corp. 参考リンクその他 • 参考リンク • http://beta.groovy-‐‑‒lang.org/docs/latest/html/documentation/ #_̲traits • http://www.artima.com/scalazine/articles/ stackable_̲trait_̲pattern.html • http://www.atmarkit.co.jp/ait/articles/1206/20/ news137_̲3.html • サンプルコード • http://groovyconsole.appspot.com/script/5738600293466112 • http://groovyconsole.appspot.com/script/5653164804014080 • 商標 • OracleとJavaは、Oracle Corporation 及びその子会社、関連会社の米国及びその他の国における登録商標です。文中の社名、商品名等は各社の商標または登録 商標である場合があります。 14年6月21日土曜日