I'm trying to write an extension function that returns true
if the value is not null
or 0 and use a contract to guarantee to the compiler that if I return true
, the value is non-null. However, it doesn't seem to be working with smart casting. It still won't compile when I try to pass the value into a function that takes a non-nullable Long
.
I tried to compile this code and it would not work. I expected the id
to be smart-casted to a Long
from a Long?
since the contract guarantees that if isValidId
returns true
then the passed in Long?
is not null.
As you can see, the property is immutable, so I don't think that's the issue. I also added some more code below, because the problem appears to be specific to extension functions. It works when I pass ID as a traditional parameter.
fun test() {
val id: Long? = null //5L
if (id.isValidID()) {
// It won't compile because the compiler says that id is a Long?
// instead of smart casting it to a Long. doWithId requires a Long.
doWithId(id)
}
}
fun doWithId(id: Long) {}
@OptIn(ExperimentalContracts::class)
fun Long?.isValidID(): Boolean {
contract { returns(true) implies (this@isValidID != null) }
return this != null && this != 0L
}
Thanks!
EDIT: Oh! It works when it's not an extension function. Does anybody know how I can make extension functions work?
fun test() {
val id: Long? = null
if (isValidID(id)) {
// This compiles now that I pass ID as a param instead of
// passing it in an extension function.
doWithId(id)
}
}
fun doWithId(id: Long) {}
@OptIn(ExperimentalContracts::class)
fun isValidID(id: Long?): Boolean {
contract { returns(true) implies (id != null) }
return id != null && id != 0L
}
inline
? That's way code that is callingisValidID
would be able to "see"this@isValidID
and optimize accordingly. Now this implication of non-nullability doesn't leave the body of the function. – Amadeo