Generic use function


#1

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)

Kotlin needs try-with-resources