Kotlin / kotlinx.coroutines

Library support for Kotlin coroutines
Apache License 2.0
12.81k stars 1.82k forks source link

Feature Request: Introduce scanNotNull Function to Flow Extension #3806

Open UdaraWanasinghe opened 11 months ago

UdaraWanasinghe commented 11 months ago

Description: I would like to request the addition of a new function, scanNotNull, to the Flow extension in the Kotlin Coroutines library. The scanNotNull function would allow folding of flow values while emitting only the intermediate non-null results.

Expected Behavior: The scanNotNull function would perform a fold operation on the flow, similar to scan or runningFold. However, it would skip emitting any intermediate results that are null. Only non-null results would be emitted in the resulting flow.

Motivation: I utilized Kotlin flows to manage UI states by converting UI actions to corresponding states. A dedicated action flow collects the necessary data for performing operations, where each action includes the required data. I employed the scan function to accumulate the necessary data for the operation. Upon collecting all data points, the operation is performed and translated into the corresponding state. Throughout the data collection process, intermediate results are communicated to the UI via events. However, not all actions are updating the data. I want them to filter out inside the scan function. See usage here: https://github.com/UdaraWanasinghe/webp-android/example/src/main/java/com/aureusapps/android/webpandroid/example/models/CodecViewModel.kt

dkhalanskyjb commented 4 months ago

Isn't your use case more straightforwardly solved via scan + distinctUntilChanged?

With your operator:

flow.scanNotNull(initialData) { data, value ->
  if (value.requiresChangingData()) {
    data.update(value)
  } else {
    null
  }
}

Without it:

flow.scan(initialData) { data, value ->
  if (value.requiresChangingData()) {
    data.update(value)
  } else {
    data
  }
}.distinctUntilChanged()

or, if update is smart enough to leave the object untouched when no update is needed, just

flow.scan(initialData) { data, value -> data.update(value) }.distinctUntilChanged()

With the additional bonus that it also works with nullable data.