Hi All! I'm looking at the coroutines code to unde...
# coroutines
a
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
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
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 🙂
e
I believe this is just the remnants of an old workaround for https://youtrack.jetbrains.com/issue/KT-16880
a
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
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
delay
probably pre-dates that.