Kotlin `use` with AutoCloseable type and a lambda returning Boolean

664 Views Asked by At

This must be simple, but I've been banging my head against it for half an hour now... Here's my old, exception-unsafe code:

fun isReady(): Boolean {
    try {
        val cc: CommandChannel = getCommandChannel()  // implements AutoCloseable
        cc.writeMessage("blahblah")
        val response = cc.readMessage()  // might throw
        cc.close()
        if (response.error == null) {
            return true
        }
    } catch (e: ChannelConnectionException) {
    }
    return false
}

I'd like to rewrite it to use use, something like this:

fun isReady(): Boolean {
    getCommandChannel().use {
        try {
            it.writeMessage("blahblah")
            if (it.readMessage().error == null) {
                return true
            }
        } catch (e: ChannelConnectionException) {
        }
        return false
    }
}

But Kotlin gives me an error:

[ERROR] X.kt:[108,29] Unresolved reference. None of the following candidates is applicable because of receiver type mismatch: 
[ERROR] @InlineOnly public inline fun <T : Closeable?, R> ???.use(block: (???) -> ???): ??? defined in kotlin.io
[ERROR] X.kt:[110,17] Unresolved reference: it
[ERROR] X.kt:[111,21] Unresolved reference: it
[ERROR] X.kt:[112,21] 'return' is not allowed here
[ERROR] X.kt:[116,13] 'return' is not allowed here
[ERROR] X.kt:[118,5] A 'return' expression required in a function with a block body ('{...}')
[ERROR] -> [Help 1]

Or, I say "okay I don't understand terse lambda syntax, let me use fun," and I try this:

fun isReady(): Boolean {
    return getCommandChannel().use(fun(cc: CommandChannel): Boolean {
        try {
            cc.writeMessage("blahblah")
            if (cc.readMessage().error == null) {
                return true
            }
        } catch (e: ChannelConnectionException) {
        }
        return false
    })
}

Kotlin still complains:

[ERROR] X.kt:[108,36] Unresolved reference. None of the following candidates is applicable because of receiver type mismatch: 
[ERROR] @InlineOnly public inline fun <T : Closeable?, R> ???.use(block: (???) -> Boolean): Boolean defined in kotlin.io
[ERROR] 
[ERROR] -> [Help 1]

My current guess is that the problem is that the CommandChannel I'm trying to use implements AutoCloseable instead of Closeable... but I don't know what I'm supposed to do about that! (Is there some sort of adaptor I need to wrap it in, maybe?) Fundamentally, I just want to make sure that cc's close method gets called correctly at the end of cc's scope, so that I'm not leaking connections.

1

There are 1 best solutions below

1
On

If you look at the Kotlin source,

public inline fun <T : Closeable?, R> T.use(block: (T) -> R): R

is available in kotlin-stdlib package (source), whereas

public inline fun <T : AutoCloseable?, R> T.use(block: (T) -> R): R

is available in kotlin-stdlib-jdk7(source) package.

So, the error that you get :

Unresolved reference. None of the following candidates is applicable because of receiver type mismatch:
[ERROR] @InlineOnly public inline fun <T : Closeable?, R> ???.use(block: (???) -> Boolean): Boolean defined in kotlin.io

indicates that since CommandChannel implements AutoCloseable and not Closeable, the use function appropriate to that is not available in your project. Try adding the dependency of kotlin-stdlib-jdk8 or kotlin-stdlib-jdk7 and you should then be able to use .use{} for CommandChannel.