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

Explicit Backing Field にちょと詳しくなる

Explicit Backing Field にちょと詳しくなる

Kotlin 2.3でExperimentalとして導入された「Explicit Backing Field」について、Kotlin Bytecodeのdecompileによる確認を交えつつ紹介します。

■DroidKaigi & iOSDC After Talks Night 2026
https://yumemi.connpass.com/event/402647/

Avatar for nyafunta9858

nyafunta9858

October 02, 2026

More Decks by nyafunta9858

Other Decks in Programming

Transcript

  1. SPEAKER プロダクト本部 Yappli開発部 Yappliアプリ1グループ ⼩林 慶弘 / にゃふんた • 2024年4⽉にヤプリに⼊社

    • 趣味:ガジェット集め、WFH環境づくり • 社内カフェのスイーツがお気に⼊り
  2. Explicit Backing Fieldとは? Explicit Backing Fieldとは? // Before private val

    _eventList: MutableList<Event> = mutableListOf() val eventList: List<Event> get() = _eventList // After val eventList: List<Event> field = mutableListOf() Backing Propertyパターン よりもシンプルに
  3. Explicit Backing Fieldとは? 問題です // ① private val _uiState: MutableStateFlow<UiState>

    = MutableStateFlow(UiState.Loading()) val uiState: StateFlow<UiState> get() = _uiState // ② private val _uiState: MutableStateFlow<UiState> = MutableStateFlow(UiState.Loading()) val uiState: StateFlow<UiState> get() = _uiState.asStateFlow() // ③ private val _uiState: Channel<UiState> = Channel() val uiState: Flow<UiState> get() = _uiState // ④ private val _uiState: MutableSharedFlow<UiState?> = MutableSharedFlow() val uiState: Flow<UiState> get() = _uiState.filterNotNull()
  4. Explicit Backing Fieldとは? 正解は... // ①:置き換え可能 private val _uiState: MutableStateFlow<UiState>

    = MutableStateFlow(UiState.Loading()) val uiState: StateFlow<UiState> get() = _uiState // ②:対象外 private val _uiState: MutableStateFlow<UiState> = MutableStateFlow(UiState.Loading()) val uiState: StateFlow<UiState> get() = _uiState.asStateFlow() // ③:対象外 private val _uiState: Channel<UiState> = Channel() val uiState: Flow<UiState> get() = _uiState // ④:対象外 private val _uiState: MutableSharedFlow<UiState?> = MutableSharedFlow() val uiState: Flow<UiState> get() = _uiState.filterNotNull()
  5. Explicit Backing Fieldとは? Decompileして⾒てみると...? // Rewrite with Explicit Backing Field

    val uiState: StateFlow<UiState> field = MutableStateFlow(UiState.Loading()) // Decompiled Code @NotNull private final MutableStateFlow uiState; public MyViewModel() { : this.uiState = StateFlowKt.MutableStateFlow(new UiState.Loading()); : } @NotNull public final StateFlow getUiState() { return (StateFlow)this.uiState; }
  6. Explicit Backing Fieldとは? 置き換えできないケースの整理 // ①:置き換え可能 private val _uiState: MutableStateFlow<UiState>

    = MutableStateFlow(UiState.Loading()) val uiState: StateFlow<UiState> get() = _uiState // ②:asStateFlowによる変換処理が必要 private val _uiState: MutableStateFlow<UiState> = MutableStateFlow(UiState.Loading()) val uiState: StateFlow<UiState> get() = _uiState.asStateFlow() // ③:Channel と Flowの間に継承関係がない、型を合わせるにはreceiveAsFlowによる変換が必要 private val _uiState: Channel<UiState> = Channel() val uiState: Flow<UiState> get() = _uiState // ④:nullability の変更のために、filterNotNull による変換が必要 private val _uiState: MutableSharedFlow<UiState?> = MutableSharedFlow() val uiState: Flow<UiState> get() = _uiState.filterNotNull()
  7. Explicit Backing Fieldとは? 置き換えできないケースの整理 // ①:置き換え可能 private val _uiState: MutableStateFlow<UiState>

    = MutableStateFlow(UiState.Loading()) val uiState: StateFlow<UiState> get() = _uiState // ②:asStateFlowによる変換処理が必要 private val _uiState: MutableStateFlow<UiState> = MutableStateFlow(UiState.Loading()) val uiState: StateFlow<UiState> get() = _uiState.asStateFlow() // ③:Channel と Flowの間に継承関係がない、型を合わせるにはreceiveAsFlowによる変換が必要 private val _uiState: Channel<UiState> = Channel() val uiState: Flow<UiState> get() = _uiState // ④:nullability の変更のために、filterNotNull による変換が必要 private val _uiState: MutableSharedFlow<UiState?> = MutableSharedFlow() val uiState: Flow<UiState> get() = _uiState.filterNotNull()
  8. KEEPから⾒るExplicit Backing Field コミュニティからはこんな提案も // KEEPの中の Proposalより引用 val city: StateFlow<String>

    field = MutableStateFlow("") get() = field.asStateFlow() 参照:https://github.com/Kotlin/KEEP/discussions/430
  9. KEEPから⾒るExplicit Backing Field 詳細はこちらから KEEP: Proposal • https://github.com/Kotlin/KEEP/blob/main/proposals/KEEP-0430-explicit-bac king-fields.md KEEP:

    Discussion • https://github.com/Kotlin/KEEP/discussions/430 YouTrack • など https://youtrack.jetbrains.com/issue/KT-14663/Support-having-a-public-anda-private-type-for-the-same-property
  10. 公式リファレンスより 制限事項(Limitations) プロパティの条件 Backing Fieldの条件 • カスタムgetterを持たない • プロパティの型のサブタイプ •

    読み取り専⽤ • 可視性はprivate • openではない • 委譲プロパティではない • コンパイル時定数(const)ではない 条件に合わない場合は、引き続きBacking Propertyパターンで回避 参照: https://kotlinlang.org/docs/properties.html#explicit-backing-fields