算譜王におれはなる!!!!

偏りはあると思うけど情報技術全般についてマイペースに書くよ。

"double context extension" pattern (命名適当) #kotlin

任意の型Aの拡張関数の中でエンクロージング型Bのメンバを使いたいとき、 次のようなコードは自然ですが、fooBの中でしか使えなくて不便です。

When we want to use a enclosing type B's members in any type A's extension function, the following code looks natural, but it's inconvenient that foo can be called in only B.

class B {
  fun A.foo() {...}
}

下記のように同じ定義を繰り返さなくてはなりません。 なぜならFragmentActivityをいじることはできないからです。

Same definitions repeat as the below code because we cannot modify the sourcecode of FragmentActivity.

class RedActivity: FragmentActivity() {
  fun DialogFragment.show(tag: String?) {
    show(supportFragmentManager, tag)
  }
}
class BlueActivity: FragmentActivity() {
  fun DialogFragment.show(tag: String?) {
    show(supportFragmentManager, tag)
  } 
}

そんなとき2つの提案があります。 1つめはインタフェースを使います。

Now I have two suggestions. The first is way to use a interface.

interface DialogFeature {
  fun getSupportFragmentManager(): FragmentManager
  fun DialogFragment.show(tag: String?) {
    show(getSupportFragmentManager(), tag)
  }
}
class RedActivity: FragmentActivity(), DialogFeature {
  fun showMessage() {
    myDialog.show("tag")
  }
}

2つめは、拡張関数を返す拡張プロパティを定義することです。

The second is way to define an extension property which return an extension function.

val FragmentActivity.show: DialogFragment.(String?) -> Unit
  get() = { tag ->
    show(supportFragmentManager, tag)
  }

class RedActivity: FragmentActivity() {
  fun showMessage() {
    myDialog.show("tag")
  }
}

myDialog.show("tag")はこう解釈できます。 「this.showプロパティが参照されたので、DialogFragmentの拡張関数を返し、myDialogをレシーバ、"tag"を引数として呼び出す」

myDialog.show("tag") can be interpreted: "this.show property was refered so it'll return DialogFragment's extension function and then call it with myDialog as a receiver and "tag" as an argument."

この方法だとIntelliJ IDEAのKotlinプラグインによる補完が効きません。 myDialog.のあとにサジェストされるメンバに、FragmentActivityの拡張プロパティであるshowは表示されません。

Code completion of IntelliJ IDEA Kotlin plugin dose not work in this way. FragmentActivity's extension property show is not suggested as myDialog's members.

私は後者が好きです。 それっぽく "double context extension" パターンと名付けます。

I prefer the later. Plausibly I named this pattern "double context extension".

(Thank you for reading this to the end. Please point out my English errors to me.)