Search code examples
kotlinkotlin-stateflowmutablestateflow

Android ViewModel MutableStateFlow Type Mismatch


When working with MutableStateFlow in my viewmodel, I got the following compile error: "Type mismatch. Required: Bar, Found: Unit"

Here is my stripped-down code:

import androidx.lifecycle.ViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.update

class Bar(
    val name : String = "",
    val id : Int = 0
)

class TestViewModel : ViewModel() {

    private val _testState = MutableStateFlow(Bar())

    fun foo() {
        _testState.update {
            it.copy(name = "fred")   // <-- error here
        }
    }

}

But when I changed Bar to data class Bar everything compiles just fine. What exactly is going on here? Why does a plain class show up as Unit whereas a data class is correctly interpreted as type Bar?

And lastly, what should I do if I want the functionality of a full class and not a data class (ie inheritance)?


Solution

  • The reason for the mention of Unit in the error: Since a non-data class doesn’t have a copy() function, the compiler doesn’t know what the return type of this supposed copy() function should be, so it’s apparently using Unit as a default inferred return type. This cascades up to a secondary error about your update lambda returning the wrong type. Basically, one error triggers another error, leading to a confusing error message.

    If you want Bar to be an open class instead of a data class you will have to manually create your own copy() function if you need one, but beware that the definition of what a copy is becomes ambiguous when there are subclasses. Probably the main reason it is forbidden to subclass a data class.

    Note that it is fine for data classes to be subclasses of other types or interfaces. They just can’t have subclasses of their own.