Kotlin contracts: link not-null of two properties

2.3k Views Asked by At

Say I have a class like this:

data class URLAndPath(
   val baseUrl: URL,
   val path: String?
) {
    val url get(): URL? =
        try { path?.let { URL(baseUrl, it) } }
        catch(_: Exception) { null }

    init { require(path == null || url != null) { "Invalid URL $baseUrl$path" } } 
}

This class ensures that if path != null if and only if url != null

Kotlin contracts seems the way to tell the compiler about these kinds of relations. Is the above invariant possible to model with Kotlin contracts?

My end result is to let code like the following compile:

val x = URLAndPath(URL("http://example.org/"), "index.html")
if(x.path != null) {
    // currently: Error: Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type URL?
    println(x.url.toURI())
}
1

There are 1 best solutions below

0
On BEST ANSWER

This does not seem possible in Kotlin 1.3, because contracts can only be on top-level functions, so not on methods.

For example

@ExperimentalContracts
data class NullableString(val s: String?) {

    fun isNotNull(): Boolean {
        contract {
            returns(true) implies (this@path != null)
        }
        return path != null
    }
}

does not compile:

Error:(16, 8) Contracts are allowed only for top-level functions
Error:(17, 39) Unresolved reference: @path
Error:(19, 15) Unresolved reference: path