Slide 1

Slide 1 text

Double Context Extension Retty Tech Cafe #8 2016-12-09 長澤 太郎

Slide 2

Slide 2 text

自己紹介 ● 長澤 太郎 たろーって呼んでね ○ @ngsw_taro ● エンジニア@エムスリー株式会社 ○ Android, Kotlin, Java, Spring, Railsなど ● Kotlinエバンジェリスト ● ディズニーが好き

Slide 3

Slide 3 text

Kotlinいいよね! ● 型推論 ● ラムダ式 ● NULL安全 ● Extension ● 委譲プロパティ ● 分解宣言 ● コルーチン ● 型エイリアス

Slide 4

Slide 4 text

Kotlinいいよね! ● 型推論 ● ラムダ式 ● NULL安全 ● Extension ● 委譲プロパティ ● 分解宣言 ● コルーチン ● 型エイリアス

Slide 5

Slide 5 text

Extension(拡張) ● 拡張関数 ● 拡張プロパティ fun String.hello() { println("Hello, $this") } "world".hello() val String.initial: Char? get()=firstOrNull()?.toUpperCase() "world".initial

Slide 6

Slide 6 text

拡張関数じゃ物足りない問題

Slide 7

Slide 7 text

こんな関数呼び出しをしたい! class MyActivity: FragmentActivity { ... fun showMessage() { // myDialog.show(supportFragmentManager, "tag") myDialog.show("tag") } }

Slide 8

Slide 8 text

こんな関数呼び出しをしたい! class MyActivity: FragmentActivity { ... fun showMessage() { // myDialog.show(supportFragmentManager, "tag") myDialog.show("tag") } } DialogFragmentに拡張関数showを生やせば? いや、プロパティsupportFragmentManagerが必要だ...  →FragmentManagerに依存

Slide 9

Slide 9 text

クラスの中に拡張関数を定義してみる class MyActivity: FragmentActivity { ... fun FragmentDialog.show(tag: String?) { show(supportFragmentManager, tag) } fun showMessage() { myDialog.show("tag") } }

Slide 10

Slide 10 text

クラスの中に拡張関数を定義してみる class MyActivity: FragmentActivity { ... fun FragmentDialog.show(tag: String?) { show(supportFragmentManager, tag) } fun showMessage() { myDialog.show("tag") } } イケる!?

Slide 11

Slide 11 text

再利用ができない問題... class MyActivity: FragmentActivity { ... fun FragmentDialog.show(tag: String?) { show(supportFragmentManager, tag) } } class YourActivity: FragmentActivity { ... fun FragmentDialog.show(tag: String?) { show(supportFragmentManager, tag) } }

Slide 12

Slide 12 text

再利用ができない問題... class MyActivity: FragmentActivity { ... fun FragmentDialog.show(tag: String?) { show(supportFragmentManager, tag) } } class YourActivity: FragmentActivity { ... fun FragmentDialog.show(tag: String?) { show(supportFragmentManager, tag) } } 同じコードが重複する

Slide 13

Slide 13 text

どうするか?

Slide 14

Slide 14 text

if (ちょっとした実験とか趣味のコード) { } else { }

Slide 15

Slide 15 text

if (ちょっとした実験とか趣味のコード) { recommend(DoubleContextExtension) } else { }

Slide 16

Slide 16 text

if (ちょっとした実験とか趣味のコード) { recommend(DoubleContextExtension) } else { recommend(Extension至上主義を捨てよ) }

Slide 17

Slide 17 text

Double Context Extension ● 2つのコンテキストを持った拡張関数 ● 命名 by 私 ● 見た目: 型Aの定義中で、型Aに依存しながらも型Bの拡張関 数を生やすことができる class MyActivity: FragmentActivity { ... fun showMessage() { myDialog.show("tag") } }

Slide 18

Slide 18 text

Double Context Extension ● 実際のコード: 「B型の拡張関数」を返す「A型の拡張プロパ ティ」を定義する // どこか適当なファイル val FragmentActivity.show: DialogFramgnet.(String?)->Unit get() { tag -> show(supportFragmentManager, tag) }

Slide 19

Slide 19 text

どう解釈されるか val FragmentActivity.show: DialogFramgnet.(String?)->Unit get() { tag -> show(supportFragmentManager, tag) } class MyActivity: FragmentActivity { fun showMessage() { myDialog.show("tag") } ... }

Slide 20

Slide 20 text

どう解釈されるか val FragmentActivity.show: DialogFramgnet.(String?)->Unit get() { tag -> show(supportFragmentManager, tag) } class MyActivity: FragmentActivity { fun showMessage() { myDialog.show("tag") } ... } FragmentActivityの 拡張関数showの呼び出し

Slide 21

Slide 21 text

どう解釈されるか val FragmentActivity.show: DialogFramgnet.(String?)->Unit get() { tag -> show(supportFragmentManager, tag) } class MyActivity: FragmentActivity { fun showMessage() { myDialog.(this.show)("tag") } ... } こう書いても同じ

Slide 22

Slide 22 text

どう解釈されるか val FragmentActivity.show: DialogFramgnet.(String?)->Unit get() { tag -> show(supportFragmentManager, tag) } class MyActivity: FragmentActivity { fun showMessage() { myDialog.show("tag") } ... } 返って来た拡張関数オブジェクトを myDialogをレシーバに、 ”tag”を引数にして呼び出す

Slide 23

Slide 23 text

まとめ ● 拡張関数って便利だよね ● でも限界がある ● Double Context Extensionという提案

Slide 24

Slide 24 text

まとめ ● 拡張関数って便利だよね ● でも限界がある ● Double Context Extensionという提案 ● 変なことしないで素直なコードを心がけましょう