why is it not possible to call Deferred::await in the Sequence::map function like it is possible in List::map?
I made a small example
fun example() = runBlocking {
val list = listOf(1, 2, 3, 4)
list.map { async { doSomething(it) } }
.map { it.await() }
list.asSequence()
.map { async { doSomething(it) } }
.map { it.await() } // Error: Kotlin: Suspension functions can be called only within coroutine body
}
As you can see the last statement does not compile.
In order to migrate to the async/await pattern, you have to return the async() result from your code, and call await() on the Deferred , from within another coroutine. By doing so, you can remove callbacks you used to use, to consume asynchronously provided values.
The launch is basically fire and forget. Async is basically performing a task and return a result. launch{} does not return anything. async{ }, which has an await() function returns the result of the coroutine.
We can wait for the coroutine to finish by calling join() on the Job. For example, suppose we have a suspend function to download some files. We can launch this coroutine and capture the resulting job, which we can later use to join — to wait for the operation to complete.
by default the methods are executed sequentially one after another. N.B:- codes are sequentially executed within a coroutine by default.
It's because list.map
is an inline fun
, which it can be because it's an eager operation that returns a new list. An inline fun
can tolerate a suspend
block because it's more like a macro: it gets expanded into the call site. As long as the call site is within a suspend
block, this works fine.
sequence.map
, on the other hand, is lazy and it just adds another lambda to the pipeline of operations that will be performed eventually, when you pull items from the sequence.
The closest match to a lazy sequence in the suspendable world is Flow
, but it has a different model where you get all the data pushed to you in one go, whereas you can pull items from a lazy sequence one by one.
Adding to Marko's answer, which is correct:
Because the sequence is lazy, the await()
call might happen after runBlocking
is done, essentially. Neither the async call nor the await will happen until you start pulling elements off the list.
And in the case of the code above, nothing pulls the elements out of the sequence, so neither of the mapping operations on the sequence would happen inside the runBlocking
block.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With