cats-effect icon indicating copy to clipboard operation
cats-effect copied to clipboard

Potential inconsistency between joinWithNever and docs

Open wunderk1nd-e opened this issue 8 months ago • 5 comments

Hi there,

In the docs for the the Spawn typeclass at the very end it states:

In English, the semantics of this are as follows:

If the child fiber completed successfully, produce its result If it errored, re-raise the error within the current fiber If it canceled, attempt to self-cancel, and if the self-cancelation fails, deadlock Sometimes this is an appropriate semantic, and the cautiously-verbose joinWithNever function implements it for you.

However, the joinWithNever implementation doesn't look like it actually makes any attempts at self cancellation and I think I've confirmed this with a small test app.

object FunTest extends IOApp.Simple {
  override val run: IO[Unit] = for {
    _ <- IO.println("Starting")
    child = IO.println("Starting child...") >>
      IO.sleep(1.second) >>
      IO.canceled >>
      IO.sleep(1.second) >>
      IO.println("Child completed")
    childFiber     <- child.start
    dependentChild <- childFiber.joinWithNever.as("I managed to return something").start
    result <- dependentChild
      .joinWith(IO.pure("I was cancelled"))
      .timeoutTo(3.seconds, "I waited too long :(".pure[IO])
    _ <- IO.println(s"result is $result")
  } yield ()
}

which outputs the following to console

Starting
Starting child...
result is I waited too long :(

Process finished with exit code 0

wunderk1nd-e avatar Jun 26 '24 16:06 wunderk1nd-e