Whats the difference b/w `coroutineScope` and `lau...
# coroutines
e
Whats the difference b/w
coroutineScope
and
launch
? (Its not super clear from the docs)
g
What is similar between them? %)
e
Tbh I’m not sure. Stems from my (mis)understanding of
coroutineScope
(I’m not entirely sure what it does)
t
launch is a method the coroutineScope is provides this method to launch a coroutine in this scope
g
coroutineScope
Creates a CoroutineScope and calls the specified suspend block with this scope
This function is designed for parallel decomposition of work. When any child coroutine in this scope fails, this scope fails and all the rest of the children are cancelled (for a different behavior see supervisorScope). This function returns as soon as the given block and all its children coroutines are completed. A usage example of a scope looks like this:
t
i guess there could be lots more of documentation of what is a CoroutineScope, what is a CoroutineDispatcher how are they connect, whats the difference and wahts a CCoroutineScope actually good for and how to use it
e
@thana not
CoroutineScope
, I understand that. Sorry I wasnt clear, I meant the builder
coroutineScope { ... }
@gildor Its sorta clear now but I need to clear something up. Will
coroutineScope
suspend the thread coroutine it is running in? (I get its a suspend function but if above is true how then does it facilitate parallel decomposition)
g
suspend the thread
This statement is incorrect by definition, you cannot suspend thread
it will suspend coroutine until all child coroutines are finished
it’s true for all suspend functions, they suspend coroutine until return
e
Yeah thats what I thought and thats why I was a bit confused.
Yeah I know that.
g
so, because coroutineScope is suspend function it will suspend until block and all child coroutines are finished
e
How then is it designed for parallel decomposition?
g
see sample
you can run child coroutines using launch/async and don’t worry about leaks, also it will wait until all of them are finished (so you can just run 2 launch coroutines and do not use join(), coroutineScope will wait)
designed for parallel decomposition
It means that you do something in parallel inside of this block
e
I see. I keep falling into the trap of thinking its about the outer coroutine scope but it really is about the inner (lambda) one. For my use case
launch
is what I need (for a side-effecty kind of thing).
Yeah I get it. Thanks @gildor
g
it doesn’t make sense to just use launch, you need multiple coroutines or some additional block
I mean:
coroutineScope { launch { doSomething() } }
doesn’t make sense
But this make sense
Copy code
coroutineScope {
launch { doSomething() }
doSomethingElse()
}
e
yeah thats not what i’m doing.
I’m doing a
launch { ... }
instead of a
coroutineScope { ... }
in the outer coroutine (which is a launch btw). It’s all cleared up now really.
g
👍
e
But I can still explain what I wanted to achieve to make it super clear. Maybe theres a better way to do what I wanted. In my project, I fetch some data (say
description
and
startedAt
) and I have to start a timer with the value of startedAt and set text with the value of description. So:
Copy code
launch {
  val data = getData() // suspend fun
  runTimer(data.startedAt)
  settext(data.description)
}

// ... elsewhere
fun runTimer(startedAt) = launch {// or coroutineScope
 // ... do timer things with ticker()
}
My confusion was whether to wrap runTimer body in coroutineScope or not, of course that wouldnt have worked because runTimer just runs a ticker that counts up forever, suspending the parent coroutine and therefore never getting to setText()
g
fun runTimer(startedAt) = launch
This is not recommended style, coroutineScope is recommended, but it has very different sematics
e
Okay that’s what I’m trying to find out now, how should this be implemented? I want to run a ticker within
runTimer
but it shouldn’t suspend the parent coroutine because I still want to reach
setText
. Also, both `launch`es are called in a larger
CoroutineScope
(my UI component) so the
launch
is not necessarily just hanging…
g
depends on runTimer implementation and how it should work
but it shouldn’t suspend the parent coroutine because I still want to reach
setText
.
Recommended approach is: launch { runTimer(data.startedAt) } suspend fun runTimer(startedAt)
e
depends on runTimer implementation and how it should work
Think of it as a loop with
delay(1000)
and
textView.text =  now - startedAt
g
yes, than like I show above
is it infinite loop?
If so, you can just convert suspend function to CoroutineScope extension
like:
Copy code
fun CoroutineScope.runTimer(…): Job {
  return launch { }
}
now it follows convention of other Kotlinx coroutine builders
e
Recommended approach is:
I see. Why is this so much different from wrapping the body in launch. The method is private so it wont be called from anywhere else.
Ah nice
g
To make it explicit
e
Yeah that actually makes a lot of sense
g
that this method starts new background coroutine on target coroutine scope
e
That is pretty clear. Thanks @gildor.
👍 1
g
Just one more reason, that you explicitly specify scope instead hide it as implementatation detail, so you can actually attach to to any scope (like in your sample), not only to top level one
1