https://kotlinlang.org logo
Title
v

Viktor Vostrikov

05/05/2020, 5:57 AM
Hello, can I pass kotlin coroutine scope as function argument? I have created question about it: https://stackoverflow.com/questions/61606630/should-you-pass-coroutinescope-as-function-argument
o

octylFractal

05/05/2020, 5:58 AM
FYI,
execute(coroutineScope: CoroutineScope, bitmap: Bitmap)
is the same as
CoroutineScope.execute(bitmap: Bitmap)
in terms of bytecode
the only difference is the source code calling convention
I'm not sure what memory leaks you're worried about, coroutines become unreachable after they finish executing -> GC can clean them up
unfortunately I'm not very well versed in android MVVM so I'm not quite sure what the exact issue is, but hopefully this clears some stuff up
v

Viktor Vostrikov

05/05/2020, 6:01 AM
Yes, I thought that it would be same in terms of bytecode. But why CoroutineScope.execute(bitmap: Bitmap) is not visible to call from another class?
o

octylFractal

05/05/2020, 6:01 AM
depends on how you're calling it, I would have to see the code. It should be available, but extension functions inside classes (i.e. not top-level) are a little quirky
v

Viktor Vostrikov

05/05/2020, 6:02 AM
ok, I will edit my post in a minute :)
I edited post
Regarding leaks, I know how coroutines work, however, I have my doubts about passing coroutine context into regular classes. I have not seen such examples. But it does make sense in our case, because that execute function is actually much larger with more context switching and even async await call.
o

octylFractal

05/05/2020, 6:09 AM
the memory model for coroutines is pretty simple, it's essentially the same as the existing model, just when the function is suspended the local variables are held by a Continuation instance. when the Continuation is no longer referenced (either because it was resumed, or the thing holding it was itself unreferenced), everything related to the function is GC-able
šŸ‘ 1
I posted an answer to the question of why it's not accessible
v

Viktor Vostrikov

05/05/2020, 6:46 AM
yes, thanks this issue is solved šŸ™‚I really appreciate it... Now regarding using launch in usecase you could be right... However, I need to call async await in my launch block. If I make execute suspending function I can't call async await without launch block... Or is there a way to call async await in suspending function, without launch block?
o

octylFractal

05/05/2020, 6:51 AM
you should probably read up on structured concurrency https://medium.com/@elizarov/structured-concurrency-722d765aa952
v

Viktor Vostrikov

05/05/2020, 6:56 AM
oh, thanks. Now I see why I can't do it with regularly, without wrapping my async await code in coroutineScope... However, this newly created coroutineScope is still managed by my outer scope, which was created with launch in VM, yes_*?*_
o

octylFractal

05/05/2020, 7:11 AM
depends on what you mean by managed, the outer scope will be the parent of the inner scope, partially explained at https://kotlinlang.org/docs/reference/coroutines/coroutine-context-and-dispatchers.html#children-of-a-coroutine
v

Viktor Vostrikov

05/05/2020, 7:16 AM
Bad formating sorry
Will create a gist for this case
Here, I will write test for this code, but so far it executes what I need. Create a long running task with withContext, wait for result and then spawn 3 parallel tasks. 2 of them are needed for await because I need results for starting a network request. 1 is not needed for await. It can take longer time for running. And then after all is done notify my repository about some changes
o

octylFractal

05/05/2020, 7:23 AM
this is mentioned in the structured concurrency docs, but
coroutineScope {}
will wait until all things started inside are completed
v

Viktor Vostrikov

05/05/2020, 7:23 AM
I am just confused about this part, which spawns async calls:
coroutineScope{
}
If I call this suspend fun with viewModelScope.launch{ } that means that coroutineScope inherits viewModelScope, yes? :)
o

octylFractal

05/05/2020, 7:23 AM
I think inherits is the wrong word here
v

Viktor Vostrikov

05/05/2020, 7:24 AM
what would be more appropriate?
o

octylFractal

05/05/2020, 7:24 AM
coroutineScope {}
really knows nothing about the
viewModelScope
, it will just take the current
coroutineContext
+
Job(coroutineContext[Job])
and create a new scope with those elements
it is some ancestor of `viewModelScope`'s
Job
, but it may not necessarily have anything else in common with it (such as dispatcher)
v

Viktor Vostrikov

05/05/2020, 7:26 AM
oh, I see... so it might not be appropriate in my case..
o

octylFractal

05/05/2020, 7:27 AM
I think it is, except for that last one which you're not
await
ing
if you want that to continue in parallel, you will need to get some sort of application scope (maybe
viewModelScope
is appropriate here) and
launch
it there
but running it based on the
coroutineScope {}
-created scope will cause your function to suspend at the end of the block until every child Job is done
šŸ‘ 1
v

Viktor Vostrikov

05/05/2020, 7:29 AM
viewModelScope acts as application scope in our case, because of SingleActivity.
Thanks.. now I get it! Like really,.. you should write some medium posts šŸ˜„ Now that you said, I still need to pass viewModelScope(same as applicationScope) as function argument to make sure that last one job is done in parallel instead of using coroutineScope, which requires to wait... yes? :D
o

octylFractal

05/05/2020, 7:39 AM
yes
v

Viktor Vostrikov

05/05/2020, 8:16 AM
Hmm, perhaps I found a better solution. Played right now. If I directly pass applicationscope instead of using coroutineScope I would not need to launch coroutine 2 times. I could do everything in one scope, running in parallel. https://gist.github.com/wellbranding/5557c920e28b11097f6d163272aa7cbe