Hey guys, I'd like your advice on an issue I'm fac...
# arrow
b
Hey guys, I'd like your advice on an issue I'm facing. So I have a screen that does an API call and shows a spinning wheel while the call is happening. All my API calls are represented as suspend functions. If I leave this screen while the call is ongoing, and come back to it, I would expect the spinning wheel to still be there, until the call is over. Alternatively, if I open another screen that depends on that same API call, I'd expect it to also show a spinning wheel, and update itself when the request comes back. In order to achieve this I need to, somehow, keep track that the call is out, and subscribe to its result rather than triggering a new call. With a non-functional approach, I would simply have a Flow in my repository and have multiple screens subscribing to it. But I don't want to do that cause it's smells like the kind of side-effects I wanna avoid. What is the best to go about this? Thanks!
c
What is the issue with
Flow
? If my understanding is correct, as long as you don't use exceptions in it, it should be fine
b
The issue with Flow is the side effect nature of it, you'd call a function that returns Unit and expect the response to come back in another part of your code, the collect block
r
Flow is a functional stream in which collect and other drain like methods are terminal like
unsafePerformIO
would be in a IO based program. Ultimately if you want pure stream composition across the board the UI itself would need to be inside Flow and you’d need control to write the
main
entry point to the program. That is probably not ergonomic or possible in Android so without looking at code I’d say you are already ok unless there is some specific code. The fact that a flow may contain Unit denotes a side effecting op inside the stream but does not make it impure. When the stream is consumed if it ends on
Unit
then that is the final value of the “Stream program” for this case.
I think unless you are in a framework like Compose that favors functions over inheritance, when we talk about FP in Android we are not talking about writing a single program as we do in CLI but rather a group of pure programs that represent use cases or encapsulate a streaming pattern. Some servers take the same approach endpoints are the end of the world for them. In Android the end of the world is the Android lifecycle methods or the compose effect handlers. Take this with a grain of salt as I know little Android.
b
Thanks a lot for this very constructive answer! Sorry, I was probably unclear about what I mean by returning
Unit
. My Flows don't return Unit, but the typical implementation of a Flow is a set of functions that make a Flow emit specific items. For example, one would call a function
fun fetchData() : Unit
and somewhere else in the code, a
collect
block would be listening for data. This patterns allows a new screen to stay up to date with a call that another/previous screen has triggered. But this is not really functional is it? Currently, my ViewModel calls the repository's suspend function returning an
ApiResponse<T>
, which allows me to create a pure function that returns a UI intent, given a specific UI input. The problem with this approach is that, since there's no side effect, it's impossible for a new screen to get updated when the response comes back
r
No problem!, I think if your function is
suspend
then it’s functional because
suspend
in the same way IO and other functional streams guarantees that if the program results in an exception is captured by the context of the
suspend
continuation. We should keep in mind that if we ever wanted to take this to the extreme we can also assert that
suspend fun
is a model for continuations. It has been proven several times ContT or the Continuation monad can model all effects and other monads so technically Kotlin is the place where people without knowing often practice principled IO and effect tracked programming.
b
Indeed, when trying to solve this problem I was first looking at the Continuation Monad but that's basically what suspend functions are. But I didn't look any further because I don't think it's going to help me here. What do you think of this
fetchData() : Unit
function and a
val dataFlow : Flow<Data>
pattern? So far it's the best way I have found for new subscriber to be notified of an ongoing call, but since it's not functional I'm worried about using it, rather than a pure function. Ideally I'd like the best of both world, having 1 function that returns an ongoing call if there's one, or makes a new call if there's none
r
I think if you make fetchData
suspend
then it’s ok. Also if Unit is confusing you can always create something like
object Ok
and use it in place of
Unit
to be explicit in the effect use sites as to what the return value is.
b
Thanks a lot!
👍 1