I’ve been playing with contracts and wanted to confirm the behaviour I’m seeing. Suppose I have the function block
defined below - I’m calling the lambda
directly, but we should imagine that this will be called outside of this execution (but still exactly once), hence we aren’t making the function inline
as lambda
would need to be noinline
anyway.
@UseExperimental(ExperimentalContracts::class)
fun block(lambda: () -> Unit) {
contract {
callsInPlace(lambda, InvocationKind.EXACTLY_ONCE)
}
lambda()
}
Because of the contract we are then able to define a val
and capture and use it between block
calls:
val list: List<Int>
block {
list = listOf(1, 2, 3)
}
block {
println(list.first()) // prints 1
}
However, curiously, if the block
contains a lambda function that uses list
, then it is no longer captured correctly, and instead you get a NullPointerException when trying to use it:
block {
println(listOf(2, 3, 4).first { list.contains(it) }) // NullPointerException as list is null
}
This can be fixed by capturing the list
first, however, you then, of course, get a warning about an unnecessary variable:
block {
@Suppress("UnnecessaryVariable")
val capturingList = list
println(listOf(2, 3, 4).first { capturingList.contains(it) })
}
Is this behaviour by design? I am using Kotlin 1.3.72. Any way of getting a compiler warning for this kind of problem, or ensuring that if a capturing value isn’t marked as unnecessary?