Search code examples
kotlinkotlin-coroutines

Passing a suspend function wrapped in a lambda


I have this data class:

data class ReportItem(val label: String, val query: () -> Unit) {
    override fun toString() = label
}

from which I want to create a list:

 val reports = listOf(ReportItem(resources.getString(R.string.sales)) { RoomDB.getInstance(requireContext()).saleItems().getBySales() })

and I get this error:

Suspend function '@Query(...) suspend fun getBySales(): List' should be called only from a coroutine or another suspend function.

I know what that means, but I think that the error is wrong. After all, I'm not calling getBySales at this point, I'm simply passing it along. Only when I call the query function in ReportItem, getBySales will actually be called (which, of course, happens inside a coroutine).

Is this a shortcoming of kotlin not being able to recognize that I'm not actually calling the suspend function? Or am I doing something wrong?


Solution

  • The idea is that you are calling getBySales within the body of this lambda. So the compiler error should not be seen as something on the lambda as a whole but on this specific line within the lambda body. Just like you would see the same error if you called this same function from the body of a non-suspend function.

    The reason why you get this error is that the type of the query parameter of this constructor is not a suspend function - it's a regular function.

    Just add the suspend keywork on its type in the declaration:

    data class ReportItem(val label: String, val query: suspend () -> Unit) {
        override fun toString() = label
    }
    

    This will, in turn, force you to call query only in suspending contexts, which is exactly what you want. This shouldn't be a problem for you because you mentioned you called it inside a coroutine.