Are Kotlin's 'coroutines' actually coroutines?

Viewed 60

The Kotlin documentation's overview of coroutines says that "Kotlin provides coroutine support at the language level, and delegates most of the functionality to libraries." But does Kotlin actually support coroutines, or are they misusing the word?

In practice what the quote from the docs means is:

  • The language provides the suspend modifier, and the compiler transforms suspend functions into CPS (continuation-passing style).
  • The kotlinx.coroutines library provides machinery for executing the resulting chains of continuations.

I haven't found a good answer for which bit of the above constitutes 'a coroutine' in Kotlin's terminology. My current best understanding is that Kotlin refers to the instance created by launch as a 'coroutine'. That fits with the slogan we see everywhere that "coroutines are light-weight threads" (for example here).

suspend fun myFunction(): Unit = delay(100)
someScope.launch { myFunction() } // this creates a 'coroutine'.

However it doesn't fit with my (admittedly thin) knowledge/experience of coroutines in other languages. Outside of Kotlin, I would describe a coroutine as a function that is like a subroutine, but can suspend and yield control to another arbitrary coroutine at any point. This definition is partly based on my reading of the Wikipedia article on Coroutines.

This is different from the way Kotlin uses the term in two major respects:

  • In Kotlin, the coroutine is the rather abstract 'lightweight thread' that executes the function, whereas by my definition, the coroutine would be the function itself.
  • Kotlin's suspend functions can only yield control back to the caller, whereas a defining characteristic of a coroutine is that it can pass control to another coroutine.

I think that Kotlin's suspend functions are actually generators or semicoroutines, and that the kotlinx.coroutines library is essentially providing a trampoline.

Is my understanding correct, based on the way the term 'coroutine' is used outside of Kotlin? If so, could the existing language support actually be used to implement something more akin to true coroutines, or is it fundamentally limited to semicoroutines and generators?

1 Answers

For me a coroutine is more like a flow of code execution, an execution context, not a function. But I agree, naming is a little inconsistent and can be confusing because traditionally we said a function is a subroutine and now we say coroutines are like threads. Even the Wikipedia article linked by you does this: first it says a coroutine is a generalization of a subroutine, but then it says coroutines are very similar to threads.

In the end of the day, I think it doesn't really matter that much. If we say we "launch a coroutine" that could mean: "launch a function which is a coroutine" or "launch a suspendable execution flow", but this is almost the same. I think this is why people use these terms for both meanings.

The main difference between subroutines and coroutines is that for subroutines the execution flow can only exit by returning from the subroutine - then the subroutine call is finished. Coroutines can temporarily suspend their execution, jump to another coroutine and after some time jump back to the place where they suspended. Coroutines in Kotlin can do that, so yes, my opinion is that they are coroutines. Although, Kotlin has to "emulate" this behavior, because most of its runtimes (JVM, JS) do not support coroutines natively.

Kotlin's suspend functions can only yield control back to the caller

What makes you think so? You can launch 5 coroutines and whenever one of them suspends, the execution jumps to the point where another coroutine suspended earlier.

Well... technically speaking yes, suspending is implemented by returning (if this is what you mean), but this is just implementation details. From the end-user perspective the execution is passed from one coroutine to another, running side-by-side.

Related