https://kotlinlang.org logo
Title
m

Miguel Vargas

07/01/2020, 6:34 PM
Calling a suspend function from a function block in a suspend function doesn’t work
private suspend fun outerSuspend() {
    timer(period = 10) {
        innerSuspend() // Error: Suspend functions can be only called within coroutine body
    }
}
It works if I create a new CoroutineScope inside the function block
private suspend fun outerSuspend() {
    timer(period = 10) {
        CoroutineScope(<http://Dispatchers.IO|Dispatchers.IO>).launch {
            innerSuspend()
        }
    }
}
Is there a way to use the outer scope in the inner block?
o

octylFractal

07/01/2020, 6:35 PM
in order to do that you need to have
timer
be
inline
or
suspend
itself
2
s

streetsofboston

07/01/2020, 7:51 PM
And if that is not possible (timer being inline/suspend), you can do this:
private suspend fun outerSuspend() = coroutineScope {
    timer(period = 10) {
        launch { innerSuspend() }
    }
}
Because creating a new
CoroutineScope
, like in your original example’s solution, breaks cancellation/structured-concurrency.
o

octylFractal

07/01/2020, 7:52 PM
hmm, but that does not actually gate the code in the
timer
you would have to explicitly
runBlocking
it to do that (or
runInterruptible
in more recent versions)
s

streetsofboston

07/01/2020, 7:53 PM
Yup. But I didn’t think that gating it was needed
g

gildor

07/01/2020, 11:55 PM
Just curious what timer does. It looks that it easier to reimplement it with coroutines than try to use non-suspend version of it, also it would make it properly cancellable
s

streetsofboston

07/02/2020, 2:49 AM
True. A
while (isActive) { 
    innerSuspend()
    delay(periodInMillis)
}
is a straightforward solution.
g

gildor

07/02/2020, 3:32 AM
yeah, if it repeat just use delay before or after innerSuspend, and remove while if you don’t need repeat and you just want wait
j

julian

07/02/2020, 4:08 AM
@octylFractal You used the term "gate". What does it mean?
o

octylFractal

07/02/2020, 4:10 AM
basically that it will "escape" outside a normal sequential execution flow, i.e. if the
timer
function was intended to cancel / interrupt / measure the inner block, it would not do so properly because
launch
immediately returns in this case
"gate" is a bit metaphorical in this case, I'm not really sure I could explain it well
j

julian

07/02/2020, 5:57 AM
I think I get it. Thanks @octylFractal!