https://kotlinlang.org logo
#flow
Title
# flow
a

abbic

10/23/2023, 9:16 AM
hi all, just a quick discussion. ive read that it's bad practice to emit from inside catching code, because we want to ensure that errors are propagated so they can be received and not just abstracted away. this makes sense, but it also means that if we forget to catch at the consumer level (eg a viewmodel) we can just end up crashing the application. is it then reasonable to instead wrap Flow error inside a kotlin Result (so that
Flow<String>
becomes
Flow<Result<String>>
for example)? are there any immediate complications from this approach? Example implementation coming soon in comments
Copy code
fun <T : Any> Flow<T>.asResultFlow(): Flow<Result<T>> = flow {
    catch {
        emit(Result.failure(it))
    }.collect {
        emit(Result.success(it))
    }
}
s

Stylianos Gakis

10/23/2023, 2:40 PM
We expose all of our flows more or less as
Flow<Either<L, R>>
and it’s super convenient. Don’t see why you wouldn’t be able to just do that. Just as long as you don’t also catch CancellationExceptions.
a

abbic

10/23/2023, 2:43 PM
is there any fundamental difference to using Either or Result? they look like they accomplish essentially the same thing
what should i be looking out for with CancellationException? i think my implementation ends up catching effectively any exception, potentially including that one. but it'd be the same anywhere you used a generic catch, right?
s

Stylianos Gakis

10/23/2023, 2:45 PM
Oh sorry didn’t mean to confuse you with that. I just use Either from arrow since I enjoy how it works https://arrow-kt.io/learn/typed-errors/working-with-typed-errors/
Yeah if you are in fact catching
CancellationException
, you need to re-throw it in that case.
a

abbic

10/23/2023, 2:46 PM
ah ok, youre saying you could equally use Either or Result (or any wrapper class for that matter)
s

Stylianos Gakis

10/23/2023, 2:46 PM
If you look inside the
internal suspend fun <T> Flow<T>.catch(
implementation, you will see they also re-throw if the catch a CancellationException. So if you only use that to catch then you’re fine already
a

abbic

10/23/2023, 2:46 PM
oh great i see
i assume it doesnt crash as its caught by the underlying coroutine scope or something?
👍 1
s

Stylianos Gakis

10/23/2023, 2:47 PM
Yes exactly, just would avoid the kotlin’s built-in result type, because it does have footguns like that,
runCatching {}
does catch CancellationException too, and does not rethrow it itself, you need to do that manually with it
Yeah then in your
viewModelScope
for example, if you use that https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:lifecycl[…]java/androidx/lifecycle/ViewModel.kt;l=35-45?q=viewModelScope It will throw the exception to the Scope, but since it uses
SupervisorJob
it will not cancel the scope, nor the other jobs working on it.
a

abbic

10/23/2023, 2:49 PM
good to know
s

Stylianos Gakis

10/23/2023, 2:49 PM
If you were not using that however, then again you need to know what you want to do with that cancellation. If you don’t have supervisorScope then it will in fact cancel the scope and all the other children and won’t let you launch more work on it
3 Views