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

Kotlinコンテキストパラメータをアプリ開発で使う夢を見る

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
Avatar for jj1uzh jj1uzh
June 30, 2026
56

 Kotlinコンテキストパラメータをアプリ開発で使う夢を見る

Avatar for jj1uzh

jj1uzh

June 30, 2026

Transcript

  1. Kotlin コンテキストパラメータとは • 2.2(experimental) → 2.4(stable) • 関数に暗黙的に引数を渡す • 渡す条件は型が一致

    or 継承すること 3 context(c: SomeContext) fun foo(n: Int) { … c.somefunc(); … } context(someContext) { foo(123) }
  2. Kotlin コンテキストパラメータとは • 一般的な使用例1: 引数の使い回し ◦ DSL 4 context(s: Session)

    fun insertUser(u: User) { // DB操作の関数がSessionを s.insert(u.asEntity) // コンテキストから取り出す } context(newTransaction()) { insertUser(user) updateUserMetadata(user.metadata) commit() }
  3. Kotlin コンテキストパラメータとは • 一般的な使用例1: 引数の使い回し ◦ コンテキスト伝搬 5 context(logger: Logger)

    fun subHoge() { … logger.debug(…); … } context(logger: Logger) fun hoge() { … logger.info(…); subHoge(); … } // 伝搬 context(newLogger(label = “MyApp”)) { hoge() }
  4. vs Function types with receivers • A.(B) -> C ◦

    ラムダ中の thisを指定 9 fun query(body: QueryBuilder.() -> Unit) class QueryBuilder { fun select(body: SelectBuilder.() -> Unit) } class SelectBuilder { fun columns(names: List<String>) } query { it.select { it.columns(…) } }
  5. vs Function types with receivers • コンテキストパラメータで書くなら ◦ 各DSLメソッドはトップレベル関数に 10

    fun query(body: context(QueryBuilder) () -> Unit): … context(q: QueryBuilder) fun select(body: context(SelectBuilder) () -> Unit) context(s: SelectBuilder) fun columns(names: List<String>) val q = query { select { columns(…) } } QueryBuilder
  6. vs Function types with receivers • コンテキストを自然に増やせる 11 fun query(logger:

    Logger, body: context(QueryBuilder) () -> Unit): … context(q: QueryBuilder, logger: Logger) fun select(body: context(SelectBuilder) () -> Unit) context(s: SelectBuilder, logger: Logger) fun columns(names: List<String>) val q = query { select { columns(…) } } QueryBuilder
  7. vs Function types with receivers • 暗黙のthis vs 暗黙の引数 •

    メリット ◦ コンテキストを自然に増やせる • デメリット ◦ DSL定義時の記述量は増える 12 QueryBuilder
  8. vs 動的なコンテキスト伝搬 • 例えばRoomDatabase.withTransaction ◦ CoroutineContextから動的に取り出す ◦ 関数シグネチャに現れない 13 @Query(“...”)

    fun createUser(u: UserEntity) // ??? database.withTransaction { createUser(user.asEntity) updateMetadata(user.asMetadataEntity) } QueryBuilder
  9. vs 動的なコンテキスト伝搬 • コンテキストパラメータだったら ◦ コンパイル時に解決 14 @Query(“...”) context(session: Session)

    // 見える化!!! fun createUser(u: UserEntity) fun withTx(body: context(Session) () -> Unit) { context(newTx()) { createUser(…) } } QueryBuilder
  10. vs 動的なコンテキスト伝搬 • 例えばCompositionLocal ◦ 子孫のCompose関数から取り出せる値を定義 15 @Composable fun ThemeText(t:String){…

    Theme.current …} @Composable fun AppScreen(){ ThemeText(“aaa”) } val Theme = compositionLocalOf { DefaultTheme() } CompositionLocalProvider(Theme provides LightTheme) { AppScreen() } QueryBuilder
  11. vs 動的なコンテキスト伝搬 • コンテキストパラメータでも ◦ recomposeも動く & コンパイル時解決 16 QueryBuilder

    @Composable context(theme: Theme) fun ThemeText(t:String){… theme …} @Composable context(theme: Theme) // ここも必要… fun AppScreen(){ ThemeText(“aaa”) } context(defaultTheme) { AppScreen() }
  12. vs 動的なコンテキスト伝搬 • メリット ◦ コンパイル時に解決 ◦ 関数シグネチャの明示 • デメリット

    ◦ 記述量 ▪ 渡すのは暗黙だけど定義は毎回必要 • interfaceにしてミックスインしていけば集約できる 17 QueryBuilder
  13. vs DI • classへのinjectionから→ 18 class DiaryRepository @Inject constructor(db: DB,

    network: DiaryNetwork){ fun publish(diary: Diary) { db.deleteDraft(diary.id) network.publishDiary(diary.data) } }
  14. vs DI • →関数ごとに依存する処理を明示 ◦ 最小権限、テストしやすさ 19 fun interface DeleteDraft

    { fun deleteDraft(id: Int) } context(d: DeleteDraft, p: PublishDiary) fun publish(diary: Diary) { d.deleteDraft(diary.id) p.publishDiary(diary.data) }
  15. 参考資料(2026-06-16閲覧) • Language Guide / Context parameters https://kotlinlang.org/docs/context-parameters.html • Kotlin

    2.2が切り拓く: コンテキストパラメータで書く関数型DSL と新しい依存管理のかたち https://speakerdeck.com/knih/context-parameters 24