kotlinx.coroutines icon indicating copy to clipboard operation
kotlinx.coroutines copied to clipboard

Introduce migration path for long-standing issue of withTimeout

Open qwwdfsad opened this issue 9 months ago • 22 comments
trafficstars

The current state of things:

  • kotlinx.coroutines.withTimeout is considered harmful -- it throws CE where it should throw TE. Enough has been written on this topic, so I won't elaborate much. Our own book, Kotlin in Action, has a dedicated note (15.2.2) about this gotcha, and it already should be enough. Would be nice to avoid a situation like this
  • kotlinx.coroutines.withTimeoutOrNull is perfectly fine.
  • kotlinx.coroutines.time.withTimeout suffers from the same decease. The time subpackage is an unfortunate pick indicating that the package (previously -- separate JAR) is interoperable with java.time entities.

Additional data:

  • On GH, withTimeout is twice as popular as withTimeoutOrNull (1 and 2)
  • Also, it is not helping: the flow.timeout() operator (luckily, under @FlowPreview), but it is also harmful when played with coroutine-launching operators (basically, anything useable).

What are our options?

  1. Breaking behavioural change. Out of the question.

  2. Come up with a new name. This one comes with its own advantages and disadvantages, namely: Pros:

    • Much easier to migrate and distinguish for readers
    • We can safely change the semantics (i.e. introduce non-atomic cancellation)
    • Can play out nicely with the new withContext if we will introduce one

    Cons:

    • A weird state of withTimeoutOrNull. Either we have semantically-similar withTimeoutOrNull and __withDeadline or we sacrifice perfectly fine withTimeoutOrNull for __withDeadlineOrNull
      • Seven+ years of common knowledge ("recognition") down the drain
  3. Reuse the same name. Originally, I had a plethora of sub-options, but the most reasonable seem to be the following:

    • Introduce kotlinx.coroutines.timeout.withTimeout version (yes, the package name for withTimeoutOrNull and withTimeout will be different)
    • Introduce @LowPriorityInOverloadResolution on the previous version(s) of withTimeout, pass it through the Beta/RC cycle. Consider marking it as Delicate?
    • Pull the trick similar to soft-deprecation of Enum.values() -- purely IDE-assisted replacement. Also, one more argument for KT-54106
    • When soft-deprecation is rolled into the major IJ/AS version, consider introducing real deprecation or @DelicateCoroutinesApi.

====

I picked the third option, and here is the draft.

If we agree that this is the way, I'll properly follow up on the PR -- documentation, guide, tests, flow operators, time subpackage, as well as proper migration path in the ticket with versioning (of coroutines and IDEA).

I would love to hear both @dkhalanskyjb stance on that as the maintainer and @SebastianAigner as the one who teaches people how to use coroutines.

qwwdfsad avatar Feb 18 '25 17:02 qwwdfsad