Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Specifying Kotlin coroutine context for each function or leaving this to the caller function? Which one is recommended?

I am new to Kotlin for Android development, and I was wondering which of the following approaches is recommended when working with Coroutine?

1. Specifying coroutine context at each function declaration

In this approach, each function will overwrite the caller context to the appropriate one.

My Assumption: The benefit is that the caller function doesn't need to know about the inners of the function it calls.

suspend fun callee() = withContext(Dispatchers.IO) {
    httpClient.get("https://google.com")
}

suspend fun caller() {
    callee()
    callee()
}

2. Delegate picking the correct context to the caller

Here, we leave the decision to the caller function, meaning it can pick any context appropriate for that use case.

Please Challenge: This lowers the code complexity and the overhead of context switching.

suspend fun callee() {
    httpClient.get("https://google.com")
}

suspend fun caller() {
    // Specify context only once
    withContext(Dispatchers.Main) {
        callee()
        callee()
    }
}

2½. Libraries already take care of this!

Since I use KTOR client, can I assume that the library already picks the correct context and I don't need to specify them?

suspend fun callee() {
    // Assumption: Ktor will run the request in correct context
    httpClient.get("https://google.com")
}

suspend fun caller() {
    callee()
    callee()
}
like image 346
Behrooz TahanZadeh Avatar asked Oct 16 '25 21:10

Behrooz TahanZadeh


1 Answers

  1. and 2.5. By design, suspend functions are required to never block the thread. That means two things:
  • We can call them directly from any other suspend function. We shouldn't need to switch the dispatcher in order to call a suspend function.
  • These functions have to correctly switch to another dispatcher if needed. Or use asynchronous processing internally.

If you see a suspend function which blocks the thread or expects to be called in a specific thread, then this function was implemented incorrectly.

Of course, we can sometimes ignore such rules when implementing an internal, private functionality inside a class. Maybe we would like to e.g. split a bigger block of code performing I/O into multiple smaller functions, but we still need them to be suspendable. In that case it probably makes sense to switch to Dispatchers.IO only once, at the entry point.

like image 64
broot Avatar answered Oct 19 '25 11:10

broot



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!