Share
Embed
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/
nyafunta9858
October 02, 2026
Transcript
16 slides
-
Explicit Backing Fieldに ちょと詳しくなる DroidKaigi & iOSDC After Talks Night
2026 @nyafunta9858 -
SPEAKER プロダクト本部 Yappli開発部 Yappliアプリ1グループ ⼩林 慶弘 / にゃふんた • 2024年4⽉にヤプリに⼊社
• 趣味:ガジェット集め、WFH環境づくり • 社内カフェのスイーツがお気に⼊り -
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パターン よりもシンプルに -
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() -
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() -
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; } -
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() -
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() -
KEEPから⾒るExplicit Backing Field コミュニティからはこんな提案も // KEEPの中の Proposalより引用 val city: StateFlow<String>
field = MutableStateFlow("") get() = field.asStateFlow() 参照:https://github.com/Kotlin/KEEP/discussions/430 -
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 -
公式リファレンスより 制限事項(Limitations) プロパティの条件 Backing Fieldの条件 • カスタムgetterを持たない • プロパティの型のサブタイプ •
読み取り専⽤ • 可視性はprivate • openではない • 委譲プロパティではない • コンパイル時定数(const)ではない 条件に合わない場合は、引き続きBacking Propertyパターンで回避 参照: https://kotlinlang.org/docs/properties.html#explicit-backing-fields -
まとめ まとめ • スマートキャストの拡張であり、同⼀オブジェクトを基底クラスで公開する 際に、簡潔な記述で安全にスマートキャストできる仕組み • 従来通りBacking Propertyパターンを使ったほうがいいシーンもある • Explicit
Backing FieldとBacking Propertyパターンの使い分けは公式情報 (Limitation)を参照のほど