Kotlin with(receiver, block) already specifies contract
Munzey opened this issue · comments
should be no need for ff87533
as with
already does this: https://github.com/JetBrains/kotlin/blob/master/libraries/stdlib/src/kotlin/util/Standard.kt#L66
But does the contract propagate through to the function in our library? Surely the compiler doesn't know how many times our function may call the block
unless we explicitly tell them?
hmm maybe I'm misundestanding why this is being added or what these types of invoke contracts are useful for. From what I've read on the addition of contracts so far, its useful for two things:
implying
something is returned to make the compiler "smarter" by foregoing checks it would usually do and letting the dev specify the "contract"- specifying how many times a lambda will be invoked, which if specified as exactly once allows the compiler to be smarter about letting one declare a val outside of the lambda, but only assigning it inside the lambda.
what is the reasoning or advantage to specifying it here?
https://kotlinlang.org/docs/reference/whatsnew13.html#contracts
Consider their example:
fun synchronize(lock: Any?, block: () -> Unit) {
// It tells compiler:
// "This function will invoke 'block' here and now, and exactly one time"
contract { callsInPlace(block, EXACTLY_ONCE) }
}
fun foo() {
val x: Int
synchronize(lock) {
x = 42 // Compiler knows that lambda passed to 'synchronize' is called
// exactly once, so no reassignment is reported
}
println(x) // Compiler knows that lambda will be definitely called, performing
// initialization, so 'x' is considered to be initialized here
}
Adapt it to the binding
function:
inline fun <V, E> binding(crossinline block: ResultBinding<E>.() -> V): Result<V, E> {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
...
}
fun foo() {
val x: Int
binding {
val a: Int = funcA().bind()
val b: Int = funcB().bind()
x = a + b // Compiler knows that lambda passed to 'binding' is called
// exactly once, so no reassignment is reported
}
println(x) // Compiler knows that lambda will be definitely called, performing
// initialization, so 'x' is considered to be initialized here
}
ok that makes sense to me now! I had to go try it out in the ide. thanks for the explanation :)