This fails in `v0.13.0` ```private fun methodThatT...
# arrow
s
This fails in
v0.13.0
Copy code
private fun methodThatThrows(): Either<Throwable, Unit> = Either.catch { throw CancellationException("") }

@Test
fun `test parTraverse`(): Unit = runBlocking {
    val result: Either<Throwable, Unit> = either {
        (1..20).parTraverse { methodThatThrows().bind() }
    }

    result shouldBe CancellationException("").left()
}
I cannot reach assertion, and throws as soon as
methodThatThrows
is called. cc: @simon.vergauwen (Sorry for tagging you on easter vacation, just want to make you aware 🙂 )
Stacktrace :
Copy code
java.util.concurrent.CancellationException: 
	at SomeTest.methodThatThrows(SomeTest.kt:12)
	at SomeTest.access$methodThatThrows(SomeTest.kt:10)
	at SomeTest$test parTraverse$1$invokeSuspend$$inlined$invoke$1$lambda$1.invokeSuspend(SomeTest.kt:17)
	at SomeTest$test parTraverse$1$invokeSuspend$$inlined$invoke$1$lambda$1.invoke(SomeTest.kt)
	at arrow.fx.coroutines.ParTraverse__ParTraverseKt$parTraverse$3$invokeSuspend$$inlined$map$lambda$1.invokeSuspend(ParTraverse.kt:180)
	at |b|b|b(Coroutine boundary.|b(|b)
	at kotlinx.coroutines.AwaitKt.awaitAll(Await.kt:42)
	at arrow.fx.coroutines.ParTraverse__ParTraverseKt$parTraverse$3.invokeSuspend(ParTraverse.kt:183)
	at SomeTest$test parTraverse$1$invokeSuspend$$inlined$invoke$1.invokeSuspend(SomeTest.kt:26)
Caused by: java.util.concurrent.CancellationException: 
	at SomeTest.methodThatThrows(SomeTest.kt:12)
	at SomeTest.access$methodThatThrows(SomeTest.kt:10)
	at SomeTest$test parTraverse$1$invokeSuspend$$inlined$invoke$1$lambda$1.invokeSuspend(SomeTest.kt:17)
	at SomeTest$test parTraverse$1$invokeSuspend$$inlined$invoke$1$lambda$1.invoke(SomeTest.kt)
	at arrow.fx.coroutines.ParTraverse__ParTraverseKt$parTraverse$3$invokeSuspend$$inlined$map$lambda$1.invokeSuspend(ParTraverse.kt:180)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
	at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
My guess is that since cancellation exceptions are meant for control flow catching them could lead to all sorts of weird behavior inside suspend functions.
s
Oh, has the implementation changed since
v0.11.0
for this ? This used to pass in the
v0.11.0
Java future throws CancellationException, ExecutionException, and InterruptedException. So it should categorised as nonFatal imo
but, thanks I can work around it by doing try catch for the time being.
I am bumping my app to 0.13.0 from 0.11.0 and a test started failing because of this
j
Tbh I am not too sure how exceptions should be classified in
Either.catch
if at all. Tho I can see the argument that it does the right thing in most cases and prevents common mistakes as catching fatal exceptions is usually a bad thing unless treated explicitly.
s
yeah, maybe doc should have left a comment or two behind the rationale 😄
s
My guess is that since cancellation exceptions are meant for control flow catching them could lead to all sorts of weird behavior inside suspend functions.
This is the rationale behind it. Kotlin has made
CancellationException
the official way of canceling a
Coroutine
. If we'd catch it inside
Either.catch
it would lead to all sorts of weird behavior and hard to debug bugs since debugging cancellation can be very painful.
Oh, has the implementation changed since 
v0.11.0
 for this ? This used to pass in the 
v0.11.0
This has indeed changed since
0.11.0
since at that point in time
CancellationException
was not the official way to cancel a
Coroutine
yet. Here is a link to
CancellationException
as it's currently defined in the Kotlin Standard Libary. https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines.cancellation/-cancellation-exception/
I'm curious though what your use-case is for catching
CancellationException
? Also if you have test that test Arrow, maybe it'd be interessting to add them to Arrow itself. Increasing our coverage is one of our next steps towards 1.0.0 and we could absolutely use the help 😉 I'd be happy to explain and help with anything you need along the way.
PS: No worries about tagging me 😉
s
Haha. I am not testing arrow 😅. But I have a similar case. So Kafka clients use Java future. And I am publishing messages to the queue parallely. So I was testing if any messages gets failed to publish, it should stop the traversing completely and give me an appropriate exception. To simulate that I used mockk library to throw CancellationException and InterruptedException from the Java future. But they don’t get caught. So I will be thrown out of the control flow. If this happens in prod, my app will crash, as the whole app based on arrow. So right now I am wrapping this method in try catch and wrapping it again in Either.catch to catch the exception I throw from the try-catch block.
I can surely write a test for that in arrow.