example use case: saving a file to disk. Does usin...
# coroutines
v
example use case: saving a file to disk. Does using suspended function + continuation make sense here?
s
The
suspendCoroutine
and its
Continuation
is mostly used for handling 3rd party (async) callbacks. I would rewrite your function to something like this:
Copy code
suspend infix fun InputStream.weaveTo(outputStream: OutputStream) = coroutineScope {
    val bytes = ByteArray(1024)
    while (true) {
        ensureActive()
        val read = read(bytes)
        if (read == -1) {
            break
        }
        outputStream.write(bytes, 0, read)
    }
}
v
what would
ensureActive()
be here exactly? I want something that gets cancelled as soon as someone cancels the outer coroutine… e.g.
job.cancel()
and reason would be avoiding further weaving from the input to the output as there still could be a lot of bytes to read/write
e
ensureActive
throws exception when cancelled.
You can do away with
coroutineScope
. Just write a suspend function and do
if (!coroutineContext.isActive) break
inside your loop. Same effect as your original code with
suspendCancellableCoroutine
. There is no reason to use it in your code. More code, but zero added value.
v
cool, less code is always better. for a while I thought
ensureActive
is a hoax (just wouldn't import 🤷‍♂️)... anyway without the
isActive
check this would otherwise run till input is exhausted, is that correct?
s
Yep. Cancelation of a coroutine does NOT interrupt a (blocking) thread.
g
Maybe I didn't get original sample, but why coroutineScope is required? Looks that you can just use suspend function. Also, you actually implicitly blocking thread and every suspend function which may call weaveTo, including Main dispatcher, which is not good You should wrap this to IO dispatcher context
Copy code
suspend infix fun InputStream.weaveTo(outputStream: OutputStream) = <http://Dispatchers.IO|Dispatchers.IO> { // shortcut for withContext
    val bytes = ByteArray(1024)
    while (coroutineContext.isActive) {
        val read = read(bytes)
        if (read == -1) {
            break
        }
        outputStream.write(bytes, 0, read)
    }
}
s
I keep forgetting there's a top level
coroutineContext
property available for suspend funs 😀
g
it available only in suspend functions, it’s language feature, not kotlinx.coroutines
also, maybe make sense to wrap
write
with
isActive
, it will make cancellation faster, because read may be pretty slow (especially for reading from network) and no need to wait also writing before cancel