Given that there exists a way for notating sequences and mixing imperative code in Kotlin, is the required code within the lambda which is argument to the sequence
function required to be thread-safe?
For example, is the following safe:
var x: Int = 5
fun someSequence(): Sequence<Int> = sequence {
while (true) {
x++
yield(x)
}
}
fun main(args: Array<String>) {
val seq = someSequence()
seq.take(200).forEach(::println)
}
Because there is no inherent parallelism to exploit when constructing sequences, I do not expect trouble with the order of operations. However, given that sequence
is implemented with help of a coroutine:
public fun <T> sequence(@BuilderInference block: suspend SequenceScope<T>.() -> Unit): Sequence<T> = Sequence { iterator(block) }
public fun <T> iterator(@BuilderInference block: suspend SequenceScope<T>.() -> Unit): Iterator<T> {
val iterator = SequenceBuilderIterator<T>()
iterator.nextStep = block.createCoroutineUnintercepted(receiver = iterator, completion = iterator)
return iterator
}
and coroutines are not fixed to a specific thread in general, I fear cached reads. I imagine two alternative scenarios:
The
sequence
function takes special care, such that the lambda which generates the next element is always executed in the same thread. Coroutines / suspend functions are an implementation detail that temporarily transfers control flow to the consumer of the sequence. Is this what@RestrictSuspension
is about? (From Is this implementation of takeWhileInclusive safe?)The lambda passed to
sequence
has to be thread-safe. Why is the documentation so tacit about this? Also tutorials only cover very simple use-cases.
Please elaborate which is case, and why.