arkivanov / Decompose

Kotlin Multiplatform lifecycle-aware business logic components (aka BLoCs) with routing (navigation) and pluggable UI (Jetpack Compose, SwiftUI, JS React, etc.)
https://arkivanov.github.io/Decompose
Apache License 2.0
2.24k stars 84 forks source link

Why does MutableValue not emit distinct values? #754

Closed eosobande closed 3 months ago

eosobande commented 3 months ago
val distinct = MutableValue(0)

distinct.subscribe { println("SUB: $it") }

distinct.update { 0 }

// RESULT
// SUB: 0
// SUB: 0
// prints twice, one for the initial subscription and again for the updated value

MutableValue::compareAndSet does not check if the value is changing or not, it just sets the new value and emits.

Proposed FIX in MutableValue::setValue:

private inline fun setValue(value: T, predicate: (T) -> Boolean = { true }): Boolean {
        lock.synchronized {
            if (!predicate(_value)) {
                return false
            }

            if (_value == value) return true // Don't do anything if value is not changing

            _value = value

            if (isEmitting) {
                return true
            }

            isEmitting = true
        }

        emit()

        return true
}
arkivanov commented 3 months ago

That's because MutableValue is similar to BehaviorSubject from RxJava. It's not necessarily a state holder, but rather an arbitrary value holder. Also, the proposed change would be a behaviour change, which is only possible with a major release (e.g. 4.0.0).

This however shouldn't not be an issue, since UI frameworks should be handling this case just fine. E.g. with Jetpack Compose, MutableValue is observed via mutableStateOf.

eosobande commented 3 months ago

Thanks @arkivanov that answers my question