is it safe to use `runCatching` in a `suspend fun`...
# coroutines
a
is it safe to use
runCatching
in a
suspend fun
when you are sure the underlying code would not throw
CancellationException
(in my case blocking file I/O stuff,
FileInputStream
etc)
y
The issue is that it'd hog the thread completely.
c
@Youssef Shoaib [MOD] why would it hog the thread? Wouldn't that happen with
runBlocking
?
y
Oh my bad I misread the question šŸ¤¦šŸ¼
c
I thought so šŸ˜… happens to the best of us
y
Yeah using
runCatching
might be okay then? Although there's other "fatal" exceptions that shouldn't be caught like OOMs. Can you give an example of how you're using it? Are you swallowing the exception and printing it or something? That's okay at the top level for instance, but I'd avoid it in something deeply nested because of OOMs and other fatal exceptions existing
a
I’m generally aware of the
runCatching
+
CancellationException
issue, but wonder if
runCatching
is ā€œsafeā€ to use inside a coroutine if it is not calling any suspend functions like so (assuming you don’t expect anything thowing Java’s
CancellationException
):
Copy code
suspend fun importNkey(uri: Uri) {
    withContext(ioDispatcher) {
        readNkeyFromFile2(uri) // plain non-suspend method calls Java blocking I/O stuff
    }.onSuccess { nkey ->
        dataStore.edit { prefs -> // edit() is a suspend fun
            // save in prefs
        }
    }
}

// not suspend !!!
private fun readNkeyFromFile2(uri: Uri): Result<NKey> =
    runCatching {
        context.contentResolver.openInputStream(uri)?.use { stream -> // throws IOException, others
            stream.bufferedReader().use { reader ->
                reader.useLines { lines ->
                    lines.first { it.startsWith(USER_SEED_PREFIX) } // throws if missing
                }
            }
        } ?: throw IOException() // openInputStream could be null if ContentProvider crashes
    }.mapCatching { seed ->
        NKey.fromSeed(seed.toCharArray()) // can throw if malformed
    }
c
Consider what happens here if any Error is thrown. For example,
OutOfMemoryError
. Your code swallows it and tries to continue doing stuff in a half-broken JVM, which may cause further problems down the stream
Result
exists to rethrow exceptions elsewhere, NOT for exception recovery
If you want to do something like this, use Arrow's
Try
or
Either
which are explicitly written to enable these kinds of behaviors