Hi All! I'm looking at the coroutines code to understand a bit more what is going under the hood and I found this in
delay()
Copy code
public suspend fun delay(timeMillis: Long) {
if (timeMillis <= 0) return // don't delay
return suspendCancellableCoroutine sc@ { cont: CancellableContinuation<Unit> ->
//some extra code
}
}
I wonder if there's a reason to do
return suspendCancellableCoroutine[...]
rather than just calling
suspendCancellableCoroutine()
, as
delay()
returns
Unit
.
z
Zach Klippenstein (he/him) [MOD]
11/05/2022, 4:44 PM
My only guess is that that tricks the compiler into a tail call optimization where it doesn’t generate a new continuation just for this function, but rather passes through the continuation from the caller?
a
Augusto
11/05/2022, 6:46 PM
That's a good point. I looked at the decompiled code, and I don't think there's a tail call optimization, but I'm not sure how a tail call optimization would look like in this case. I can see that there's a new coroutine created (by
suspendCancellableCoroutine()
), but I'm not sure if there's some extra magic 🙂
Thank you ephemient and Zach! I appreciate your help. I wrote a couple of examples to see how the state machine of the continuations looks in bytecode and how the tail optimization avoids it.
I just started to learn coroutines a few days ago and I wasn't aware of this optimization. Looking through the docs, I cannot find it being mentioned, but sounds like it's something to be aware of to write performant code.
e
ephemient
11/05/2022, 10:24 PM
this is not something that anybody currently writing Kotlin code should need to worry about. the issue is marked as resolved, what you see in