Upgrade to Pro — share decks privately, control downloads, hide ads and more …

KotlinでPhantom Type #kotlin_sansan

KotlinでPhantom Type #kotlin_sansan

第2回Kotlin勉強会 @ Sansan

Jumpei Yamamoto

March 24, 2016
Tweet

More Decks by Jumpei Yamamoto

Other Decks in Programming

Transcript

  1. Copyright  ©  Sansan,  Inc.  All  rights  reserved.
    > KotlinでPhantom  Type
    第2回Kotlin勉強会  @Sansan  
    #kotlin_̲sansan  
    2016.  3.  24  
    @boohbah  

    View Slide

  2. Copyright  ©  Sansan,  Inc.  All  rights  reserved.
    > ⾃自⼰己紹介
    - ⼭山本純平  
    - Sansan株式会社  Eight事業部    
    - EightのAndroidアプリの開発  
    - twitter:  @boohbah  
    - github:  https://github.com/yamamotoj  

    View Slide

  3. Copyright  ©  Sansan,  Inc.  All  rights  reserved.
    > DroidKaigi  2016

    View Slide

  4. Copyright  ©  Sansan,  Inc.  All  rights  reserved. 4

    View Slide

  5. Copyright  ©  Sansan,  Inc.  All  rights  reserved.
    > Eightの新機能「オンライン名刺刺交換」
    - もう紙の名刺刺はいらない!  
    - NearByで周囲のEightユー
    ザーを検索索  
    - 複数のユーザー間でも名刺刺
    交換ができる

    View Slide

  6. Copyright  ©  Sansan,  Inc.  All  rights  reserved.
    6

    View Slide

  7. Copyright  ©  Sansan,  Inc.  All  rights  reserved.
    7

    View Slide

  8. Copyright  ©  Sansan,  Inc.  All  rights  reserved.
    8

    View Slide

  9. Copyright  ©  Sansan,  Inc.  All  rights  reserved.

    View Slide

  10. Copyright  ©  Sansan,  Inc.  All  rights  reserved.
    10
    KotlinͰ
    Type

    View Slide

  11. Copyright  ©  Sansan,  Inc.  All  rights  reserved.
    > Phantom Type (༓ྶܕ)
    - Πϯελϯεͷঢ়ଶΛܕύϥϝʔλͰ࣋ͭ͜ͱʹΑͬ
    ͯɺঢ়ଶͷνΣοΫΛίϯύΠϧ࣌ʹߦ͏ɻ
    - ঢ়ଶΛද͢ܕύϥϝʔλ͸࣮ࡍʹ࢖ΘΕΔ͜ͱ͕ͳ
    ͘ɺίϯύΠϧ࣌ʹফ͑ͯ͠·͏ɻ

    View Slide

  12. Copyright  ©  Sansan,  Inc.  All  rights  reserved.
    > 実際に⾒見見てみましょう
    sealed  class  State  {  
           class  NotReady  :  State()  
           class  Ready  :  State()  
    }  
    data  class  Data(val  a:  Int)  {  
    }  
    これが  Phantom  Type
    型パラメータは実⾏行行時に消
    去されるため、Stateクラ
    スが使⽤用されることはない

    View Slide

  13. Copyright  ©  Sansan,  Inc.  All  rights  reserved.
    > 引数で振り分け
    fun  show(data  :Data)  =  
             print(“Not  ready!!”)  
    fun  show(data:  Data)  =  
           print(“ready!!”)  
    fun  bar(data:  Data)  =  
           print(“bar!”)
    val  d1  =  Data(2)  
    show(d1)  //  -­‐>  Not  ready!!  
    bar(d1)    //  ίϯύΠϧΤϥʔ  
    val  d2  =  Data(2)  
    show(d2)  //  -­‐>  ready  !!  
    bar(d2)    //  -­‐>  bar!  

    View Slide

  14. Copyright  ©  Sansan,  Inc.  All  rights  reserved.
    > 拡張関数と併⽤用する
    fun  Data.ready()  =  Data(a)  
    fun  Data.say()  =  print(“I’m  ready!!”)  
     val  d1  =  Data(2)  
     val  d2  =  d1.ready()  //  Data  
    d1.say()      //  ίϯύΠϧΤϥʔ  
    d2.ready()  //  ίϯύΠϧΤϥʔ  
    d2.say()      //  -­‐>  I;m  ready!!          
       d1  ==  d2    //  True

    View Slide

  15. Copyright  ©  Sansan,  Inc.  All  rights  reserved.
    > 利利⽤用シーン

    View Slide

  16. Copyright  ©  Sansan,  Inc.  All  rights  reserved.
    > 例例えば簡単なSQL⽂文を出⼒力力するDSLを考えてみる
    Query  
           .select("*")  
           .from("Person")  
           .where("ID  =  1")  
           .print()  
    //  -­‐>  SELECT  *  FROM  Person  WHERE  ID  =  1;  

    View Slide

  17. Copyright  ©  Sansan,  Inc.  All  rights  reserved.
    > クラスと状態の定義
    //  -­‐>  SELECT  *  FROM  Person  WHERE  ID  =  1;  
    sealed  class  Status  {  
           class  From  :  Status()   //  From۟ΛೖྗͰ͖Δঢ়ଶ  
           class  Where  :  Status()    //  Where۟ΛೖྗͰ͖Δঢ়ଶ  
           class  Print  :  Status()    //  ݁ՌΛग़ྗͰ͖Δঢ়ଶ  
    }  
    //  Queryੜ੒Ϋϥεͷఆٛ  
    class  Query(  
                   val  column:  String,  
                   val  tableName:  String,  
                   val  predicate:  String)  

    View Slide

  18. Copyright  ©  Sansan,  Inc.  All  rights  reserved.
    > メソッドの定義
    class  Query(  
                   val  column:  String,  
                   val  tableName:  String,  
                   val  predicate:  String)  {  
    }  

    View Slide

  19. Copyright  ©  Sansan,  Inc.  All  rights  reserved.
    > メソッドの定義
    class  Query(  
                   val  column:  String,  
                   val  tableName:  String,  
                   val  predicate:  String)  {  
           companion  object  {  
                   fun  select(column:  String)  =    
                             Query(column,  "",  "")  
           }  
    }  
    Query型  
    のオブジェクトを⽣生成

    View Slide

  20. Copyright  ©  Sansan,  Inc.  All  rights  reserved.
    > メソッドの定義
    class  Query(  
                   val  column:  String,  
                   val  tableName:  String,  
                   val  predicate:  String)  {  
           companion  object  {  
                   fun  select(column:  String)  =    
                             Query(column,  "",  "")  
           }  
    }  
    fun  Query.from(tableName:  String)  =  
                   Query(this.column,  tableName,  this.predicate)  
    Query型  
    のオブジェクトを⽣生成
    Query型  
    からしか呼び出せない

    View Slide

  21. Copyright  ©  Sansan,  Inc.  All  rights  reserved.
    > メソッドの定義
    class  Query(  
                   val  column:  String,  
                   val  tableName:  String,  
                   val  predicate:  String)  {  
           companion  object  {  
                   fun  select(column:  String)  =    
                             Query(column,  "",  "")  
           }  
    }  
    fun  Query.from(tableName:  String)  =  
                   Query(this.column,  tableName,  this.predicate)  
    fun  Query.where(predicate:  String)  =  
                   Query(this.column,  this.tableName,  predicate)  
    Query型のオブジェクトを⽣生成
    Query型  
    からしか呼び出せない

    View Slide

  22. Copyright  ©  Sansan,  Inc.  All  rights  reserved.
    > メソッドの定義
    class  Query(  
                   val  column:  String,  
                   val  tableName:  String,  
                   val  predicate:  String)  {  
           companion  object  {  
                   fun  select(column:  String)  =    
                             Query(column,  "",  "")  
           }  
    }  
    fun  Query.from(tableName:  String)  =  
                   Query(this.column,  tableName,  this.predicate)  
    fun  Query.where(predicate:  String)  =  
                   Query(this.column,  this.tableName,  predicate)  
    fun  Query.print()  =  
                   "SELECT  $column  FROM  $tableName  WHERE  $predicate  ;"
    Query型  
    からしか呼び出せない

    View Slide

  23. Copyright  ©  Sansan,  Inc.  All  rights  reserved.
    > 結果
    Query  
           .select(“*”)          //  Query  
           .from(“Person")    //  Query  
           .where("ID  =  1”)  //  Query    
           .print()  
    //  -­‐>  SELECT  *  FROM  Person  WHERE  ID  =  1;  

    View Slide

  24. Copyright  ©  Sansan,  Inc.  All  rights  reserved.
    > まとめ
    - Kotlinでも型レベルプログラミング!

    View Slide

  25. Copyright  ©  Sansan,  Inc.  All  rights  reserved.
    > おまけ

    View Slide

  26. Copyright  ©  Sansan,  Inc.  All  rights  reserved.
    > お気に⼊入りの拡張関数
    fun    T.log(  
                   tag:  String  =  "my-­‐debug",  
                   to_string:  (T)  -­‐>  String  =  {  it.toString()  }  
    ):  T  {  
           Log.d(tag,  to_string(this))  
           return  this  
    }

    View Slide

  27. Copyright  ©  Sansan,  Inc.  All  rights  reserved.
    > お気に⼊入りの拡張関数
    fun    T.log(  
                   tag:  String  =  "my-­‐debug",  
                   to_string:  (T)  -­‐>  String  =  {  it.toString()  }  
    ):  T  {  
           Log.d(tag,  to_string(this))  
           return  this  
    }
    fun  getHoge()  =  A().let{  transform(it)  }.B()  

    View Slide

  28. Copyright  ©  Sansan,  Inc.  All  rights  reserved.
    > お気に⼊入りの拡張関数
    fun    T.log(  
                   tag:  String  =  "my-­‐debug",  
                   to_string:  (T)  -­‐>  String  =  {  it.toString()  }  
    ):  T  {  
           Log.d(tag,  to_string(this))  
           return  this  
    }
    fun  getHoge()  =  A().log().let{  transform(it)  }.B()  
    Single  Expression形式でもlogを出せる

    View Slide

  29. Copyright  ©  Sansan,  Inc.  All  rights  reserved.
    > お気に⼊入りの拡張関数
    fun    T.log(  
                   tag:  String  =  "my-­‐debug",  
                   to_string:  (T)  -­‐>  String  =  {  it.toString()  }  
    ):  T  {  
           Log.d(tag,  to_string(this))  
           return  this  
    }
    fun  getHoge()  =  A().log(){  “a:”  +  it.toString()  }  
    .let{  transform(it)  }.B()  
    任意の⽂文字列列に変換可能

    View Slide

  30. Copyright  ©  Sansan,  Inc.  All  rights  reserved.
    > お気に⼊入りの拡張関数
    fun    T.log(  
                   tag:  String  =  "my-­‐debug",  
                   to_string:  (T)  -­‐>  String  =  {  it.toString()  }  
    ):  T  {  
           Log.d(tag,  to_string(this))  
           return  this  
    }
    fun  getHoge()  =  A().log(“my_tag”){  “a:  $it”  }  
    .let{  transform(it)  }.B()  
    タグも変更更できる

    View Slide

  31. Copyright  ©  Sansan,  Inc.  All  rights  reserved.
    > おまけ2

    View Slide

  32. Copyright  ©  Sansan,  Inc.  All  rights  reserved.
    > Raw  Textリテラル便便利利
    val  json  =  """  
    {  
           "name":  yamamotoj,  
           "url":  "https://github.com/yamamotoj",  
    }  
    """
    //  Java  
    String  json  =  "{\n"  +  
                   "        \"name\":  yamamotoj,\n"  +  
                   "        \"url\":  \"https://github.com/yamamotoj\",\n"  +  
                   "}\n";  

    View Slide

  33. $PQZSJHIU˜4BOTBO *OD"MMSJHIUTSFTFSWFE

    4BOTBO͸Ұॹʹ৽͍͠Ձ஋Λ࡞͍ͬͯ͘
    ஥ؒΛ͕͍ͯ͞͠·͢ɻ
    3VCZ 3VCZPO3BJMT
    ʢ8FCΞϓϦέʔγϣϯʣ
    $ɼ"41/&5.7$
    ʢ8FCΞϓϦέʔγϣϯʣ
    J04"OESPJEΞϓϦ
      ݸਓ޲໊͚ࢗ؅ཧΞϓϦʮ&JHIUʯ
      ໊ࢗσʔλԽ෼ࢄॲཧγεςϜ
      ๏ਓ޲໊͚ࢗ؅ཧαʔϏεʮ4BOTBOʯ
      ๏ਓ޲໊͚ࢗ؅ཧαʔϏε
    ʮ4BOTBOʯ
      ݸਓ޲໊͚ࢗ؅ཧΞϓϦʮ&JHIUʯ
    ΤϯδχΞืूத
    4BOTBO࠾༻ ݕࡧ
    SFDSVJU!TBOTBODPN·Ͱ
    ͓ؾܰʹ͝࿈བྷ͍ͩ͘͞ɻ
    ڵຯͷ͋Δํ͸

    View Slide

  34. Copyright  ©  Sansan,  Inc.  All  rights  reserved.
    > Thank  you
    34

    View Slide