```fun main(){ println("Am starting off") ...
# getting-started
t
Copy code
fun main(){
    println("Am starting off")
    runBlocking {
        println("test is over" +coroutineTest())
    }
    println("Am finishing off")
}
fun coroutineTest(): Boolean{
    CoroutineScope(Dispatchers.Default).launch {
        for ( i in 1..20){
            println("I am alive $i")
        }
    }
    return true
}

Output:
Am starting off
test is overtrue
I am alive 1
I am alive 2
I am alive 3
I am alive 4
I am alive 5
I am alive 6
I am alive 7
I am alive 8
I am alive 9
I am alive 10
I am alive 11
Am finishing off
I am alive 12
I am alive 13
I am alive 14
I am alive 15
I am alive 16
I am alive 17
I am alive 18
I am alive 19
I am alive 20
tried out above code and now am confused why the coroutines still lives even after function finishes off i thought the coroutineContext ensures coroutine doesn't outlives the scope even adding ensureActive() doesn't make any difference but taking it out from runBlocking works as expected why?
p
From my understanding nothing in your code tells the coroutine to stop or be cancelled. Your code basically runs: • print “Am starting off” • create run blocking scope. Call a function that launches coroutine and print true immediately. • print “Am finishing off” In the run blocking scope you launch some coroutine on the Default dispatcher thread pool. But nothing tells those coroutines to cancel?
f
CoroutineScope(Dispatchers.Default) is detach from coroutineTest, there are not in the same context
p
Also the coroutine is not cooperative in the sense that it has no suspension points (delay, yield); nor does it check: ensureActive() or isAlive. Therefor it does not care whether it’s being cancelled. I might be wrong though.
f
it should be something like
Copy code
suspend fun coroutineTest(): Boolean =
    withContext(Dispatchers.Default) {
        for (i in 1..20) {
            println("I am alive $i")
        }
        true
    }
🙌 1
t
@Pim i did this to check whether the coroutine still runs even after function returns what i expected was it might cancel and stop executing but it doesn't, even i tried adding
ensureActive()
just after
println("I am alive $i")
but the behaviour remains same.
@François Oh can you expand on this detachment or tag doc. Secondly why taking
coroutineTest()
out of
runBlocking
works fine
j
t
@jamshedalamqaderi well i was asking for that specific part
j
So
CoroutineScope(Dispatchers.Default).launch
will detach from
runBlocking
context and run in background
t
@jamshedalamqaderi so does that mean control over it can only be established using the job and there is complete detachment from calling function? secondly why removing the runBlocking makes it work like expected which is the coroutine immediately stops execution
j
So,
runBlocking
is made for execute suspending works in non-suspending functions.
t
@jamshedalamqaderi I know that part but how does it translate to this behaviour It might be trivial for you but not for me could you explain the workflow
j
Can you show the output without
runBlocking
?
t
@jamshedalamqaderi here it is Am starting off test is overtrue Am finishing off
j
I'm getting different:
Copy code
Am starting off
Test is over : true
Am finishing off
I am alive 1
I am alive 2
I am alive 3
I am alive 4
I am alive 5
I am alive 6
I am alive 7
I am alive 8
I am alive 9
I am alive 10
I am alive 11
I am alive 12
I am alive 13
I am alive 14
I am alive 15
I am alive 16
I am alive 17
I am alive 18
I am alive 19
I am alive 20
t
@jamshedalamqaderi
j
I think before scheduling the dispatcher the program ends. try a applying a little bit of
Thread.sleep()
before
return true
t
@jamshedalamqaderi I tried and you rightly pointed out . so it means if the program ends earlier the scheduling stops otherwise it will run to completion? like there's no connection between function and launched coroutine if created this way without storing job
j
If Job is created successfully then it will run until internal works has finished. So, you need to take care of the job
🙌 1
t
@jamshedalamqaderi thanks 🙌 what about my second statement
j
which one?
t
@jamshedalamqaderi the connection between the function and coroutine . I find it hard to digest
j
Can you elaborate more on this question. I didn't understand properly.
t
@jamshedalamqaderi coroutineTest is the site where the coroutine was launched and for every suspendable work Kotlin stores the stack frame so in this regard shouldn't the coroutine be someway attached to the function like if the function returns meaning it will be off from stack so it's stack frame, so what will happen to coroutine I don't know, am i making sense or not🥲
j
if you want to return any value then you need to use
suspend
keyword in a function and finally if you want to execute it from
main
function then use
runBlocking
, So it will hold the main function running until
suspending
function is finished. But
CoroutineScope
need to be managed by you
🙌 1
t
@jamshedalamqaderi i get it, thanks again
👍 1
j
@Tushar I've made an example for an use case regarding to
CoroutineScope
that i have used in my projects. You could take another example to run long running task on cron jobs
Copy code
// kotlin
fun main() {
    println("Start of the main")
    runBlocking {
        val worker: Worker = PrimaryWorker()
        if (!worker.isRunning) {
            println("Worker is not running. Starting...")
            worker.run()
        }
        delay(10.seconds)
        if (worker.isRunning) {
            println("Worker is still running. Stopping it")
            worker.stop()
        }
        delay(1.seconds)
    }
    println("End of the main")
}

class PrimaryWorker : Worker {
    private var job: Job? = null

    override val isRunning: Boolean
        get() = job != null && job?.isActive == true

    override fun run() {
        job = CoroutineScope(Dispatchers.IO).launch {
            while (isActive) {
                delay(1.seconds)
                println("Running from primary worker")
            }
        }
        job?.invokeOnCompletion {
            println("Primary worker job is completed: ${it?.message}")
        }
    }

    override fun stop() {
        job?.cancel("Stopping manually")
    }

}

interface Worker {
    val isRunning: Boolean
    fun run()
    fun stop()
}
🙌 1
t
@jamshedalamqaderi Great example, makes it more clear
1