Wednesday, 7 September 2022

Smart cast to 'Type' is impossible, because 'x' is a mutable property that could have been changed by this time

So I run into this problem quite often lately, most of the time it happens when I have defined a Hibernate Entity in Kotlin, and I wish to use it in my code.

It happens when there's a property that could conceivably be accessed in another thread, cause the two statements, the if-statement and the execution statement to look at different states, and cause a ClassCastException.

The following code demonstrates the message Kotlin provides when writing such a program:

private var name: String? = null
/**
* This does not compile, because after the if and before the assert, name could have been change
* in another thread on this object.
*/
@Test
fun mutablePropertyCouldHaveChanged1() {
if (name != null) {
// assertThat(name.length).isNotZero()
}
}

Possible solutions

/**
* if we're sure, we can just brute-force is and tell Kotlin that we're sure the property is never null
* here. I don't like this. Could be a thread-safety issue.
*/
@Test
fun mutablePropertyCouldHaveChanged2() {
if (name != null) {
assertThat(name!!.length).isNotZero()
}
}
/**
* create a local variabel so we're sure it is not a problem.
*/
@Test
fun mutablePropertyCouldHaveChanged3() {
val local = name
if (local != null) {
assertThat(local.length).isNotZero()
}
}
/**
* use "?.let" to create a lambda in which we're sure there's no problem.
* Is a very nice solution, if possible.
*/
@Test
fun mutablePropertyCouldHaveChanged4() {
name?.let { assertThat(it.length).isNotZero() }
}

References

Youtube - Let, Also, Apply, Run, With - Kotlin Scope Functions
https://www.youtube.com/watch?v=Vy-dS2SVoHk