We have a SharedFlow to avoid duplicated resource ...
# coroutines
j
We have a SharedFlow to avoid duplicated resource fetching (network, parsing). When some runtime non-domain exception happen, we let the exception (e.g. IOException) to be thrown and processed in ViewModels (e.g. show no internet connection toast - i.e. a general handling is reused here). But SharedFlow does not distribute the exception downstream and rather crashes (throws it on its coroutine scope). What is the motivation here? Why not rethrow the exception for particular downstreams? We can wrap the stuff to some Result type but we wanted to avoid this for general runtime errors, we use it just for domain state modeling (e.g. error type is for ShortPassword error)
m
I don’t know the official answer, but i guess it is because it is ‘Shared’. How would you reThrow exception downstream to multiple subscribers? What if a new subscription opens just before an exception. Shared/State is designed to model state - in which, if an exception occur, you should model it as a specific state upstream, rather that propagating the exception downstream to multiple subscribers, which imo doesn’t make sense
j
I would not rethrow any exception (except for cancellation exceptions) in kotlin anyway. Without having checked exceptions you will have no idea where they will end up, as well as a shared flow is basically a channel that sends out values. So it is not "just a flow" under the hood and therefore if you want it to have a result in all the observers (and an exception is a sort of result if you think about it) then you will have to wrap it in a result object. I strongly advice everyone to stop messing with flows onCatch or whatever methods, and instead pass values and exceptions wrapped within result object. It is much more concise and you will not have the surprise runtime exceptions in your face because you never got a compiler warning about missing a checked exception.
j
I don't think not using exception is a good thing. To be precise, we stick exactly with Elizarov's recommendation: https://elizarov.medium.com/kotlin-and-exceptions-8062f589d07
The default in Kotlin is to use exceptions for input/output. This way you can write dense logic of your code, without having to worry about potential network errors that each individual call could produce
...
You should not be writing boilerplate code to handle a potential network error in each individual network request in your application’s logic.
m
You should not be writing boilerplate code to handle a potential network error in each individual network request in your application’s logic.
Ya, kind of. You have to write boilerplate anyway, being it an exception or a sealed class. So, you can map in the UI either an exception or an error sealed class either way,
n
Motivation is detailed in Error Handling section of Introduce SharedFlow #2034 issue.