Currently the use
function can only be used on Closeable
, limiting the targets where this function can be used to the JVM. I think a more generic variant of this function is useful, so the same pattern can be used for any class with a close/dispose/… method, and on any target.
Here is a proof of concept. For each specific type on which use
must be called, 2 additional declarations are needed, but these declarations are short and simple:
// Shared by all targets
inline fun <T, R> T.use(closerBlock: T.() -> Unit, block: (T) -> R): R {
var closed = false
try {
return block(this)
} catch (e: Exception) {
closed = true
try {
this.closerBlock()
} catch (closeException: Exception) {
}
throw e
} finally {
if (!closed) {
this.closerBlock()
}
}
}
fun <T : Any> asCloserBlock(closerBlock: T.() -> Unit): T?.() -> Unit = { this?.closerBlock() }
// JVM target
// Inlining this value results in the following error:
// required: T.() -> Unit
// found: Closeable?.() -> Unit
val closeableClose = asCloserBlock(Closeable::close)
inline fun <T : Closeable?, R> T.use(block: (T) -> R) = use(closeableClose, block)