Tian Tian098
03/21/2025, 5:23 PMval myResource: Deferred<Closeable> = coroutineScope.async(LAZY) { ... }
What is the best way to close that resource if it has been created? So far I have
fun Deferred<Closeable>.close(coroutineScope: CoroutineScope) {
when {
isActive || isCompleted -> coroutineScope.launch { await().close() }
else -> cancel()
}
}
That seems really complicated for what I'm trying to do thoughTian Tian098
03/21/2025, 5:30 PMisActive and isCompleted properly, and maybe if there is some standard-library function I missedkevin.cianfarini
03/21/2025, 5:31 PMsuspend fun Deferred<Closeable>.close() {
await().close()
}Tian Tian098
03/21/2025, 5:33 PMawait() will create it just for it to be closed...kevin.cianfarini
03/21/2025, 5:40 PMfun Deferred<Closeable>.close() {
val closeable = try {
getCompleted()
} catch (e: IllegalStateException) {
// Suppress.
null
}
closeable?.close()
}kevin.cianfarini
03/21/2025, 5:41 PMTian Tian098
03/21/2025, 5:46 PMephemient
03/21/2025, 7:58 PMmyResource.invokeOnCompletion { e ->
if (e == null) cleanup()
but LAZY is sorta tricky for other reasons: even if it's never started, its existence prolongs the parent scope/jobviluon
03/22/2025, 8:58 AMflow {
resource.use {
emit(it)
awaitCompletion()
}
}
Now you have a cold flow that won't open the resource until you start collecting it (change resource to an expression that opens a file, for example). But the resource will only be closed after you're done working with it in downstream flow operators. You can work with the resource in collect, or change it with map and eventually ask for first() if you need the result outside the flow.
To turn that into a Deferred, you can eventually do async { resourceFlow.first() }, but note that the resource will already be closed by the time you await this expression. Therefore, stateful transformations are a better fit for the flow operators, if you can live with the fact that only the result of all the operations is Deferred.viluon
03/22/2025, 9:01 AMDeferred<Closeable> into this idiom by awaiting it in the flow {} block.Tian Tian098
03/23/2025, 4:00 PMval myResource = lazy { coroutineScope.async { ... } }
This turns out to be faster because it creates the coroutine lazily instead of async(LAZY) { ... } which creates the coroutine eagerly and just starts it lazily.
The corresponding close function looks like
fun Lazy<Deferred<Closeable>>.close(coroutineScope: CoroutineScope) {
if (isInitialized()) coroutineScope.launch {
value.await().close()
}
}