Been converting Rx `Singles`, `Maybes`, and `Compl...
# coroutines
m
Been converting Rx
Singles
,
Maybes
, and
Completables
to
suspend
functions. I feel that with Rx, error handling is pretty much
try/catch(Throwable)
behind the scenes. So when switching over to coroutines, one might "naively" start using
runCatching { ... }.onSuccess { ... }.onFailure { ... }
or basic
try/catch(Throwable)
. The issue with this is that a
CancellationException
will also be caught when attempting to cancel a coroutine. Does this mean that before refactoring to
suspend
functions, one should begin defining custom, domain-specific Exceptions or leverage some sort of
Result
type in order to avoid
try/catch(Throwable)
?
l
There are multiple solutions to this problem. One is to have an empty
catch(ignored: CancellationException)
first, or from which you rethrow (important if there's only custom suspending functions that don't check for cancellation). Another is to catch only the expected exceptions (might be risky if you don't know what can be thrown). You can also check
e is CancellationException
and rethrow it.
m
Thank you for your reply!
If I understand correctly, if I were to try and port over existing non-Observable Rx code, with minimal changes, it would go from
Copy code
doRxAsyncWork()
    .subscribeOn(...)
    .observeOn(...)
    .subscribe(
        { ... },
        { error -> // perform error handling }
    )
to
Copy code
try {
    doSuspendingWork()
} catch (ex: CancellationException) {
    throw ex
} catch (ex: Throwable) {
    // perform error handling
}
👌 1
Thanks again! IMO, this does not look as nice as Rx. It does become a harder sell for people who are perfectly happy with RxJava.
One can probably define their own custom
runCatching
utility that catches and re-throws the
CancellationException
.
s
Yup, I found the same issue. It seems Kotlin here is almost forcing you to never catch exceptions with a broad/wide net. It is indeed better to catch specific exceptions instead of
Exception
, or
Throwable
, etc. In this case it is somewhat forced on you to catch specific ones only
m
In general, it has always been good practice to catch specific exceptions. Unfortunately, Rx made it way to easy to overlook this. The issue now is trying to refactor existing non-
Observable
Rx code to
suspend
functions with minimal effort.
p
Or you don't go the minimal efford way and find erros in your code 😉
☝️ 1
m
It seems
Flows
will be getting a
catch
operator that properly handles
CancellationExceptions
. “Exceptions in Kotlin Flows” by Roman Elizarov https://link.medium.com/AenSuqlckY
@elizarov any chance we'll be getting a
runCatching
variant for non-
Flow
suspend
code that also takes
CancellationExceptions
into account?
s
I think you mischaracterized “error handling” as transparent in rx. There are explicit operators to force you to address them because they might happen asynchronously and they don’t suspend/resume to rethrow in the current thread. You actually can’t not deal with errors
i expect Flow to catch up and have a similar operator vocabulary soon enough