```private fun UserContact?.isValid(): Boolean { ...
# getting-started
m
Copy code
private fun UserContact?.isValid(): Boolean {
    contract {
        returns(true) implies (this@isValid != null)
    }
    return this != null &&
        userId.isNotBlank() &&
        !email.isNullOrBlank() &&
        !phoneNumber.isNullOrBlank()
}
Copy code
suspend operator fun invoke(): UserData {
        val userData = getUserData()
        val contact = getUserContact()
        return when {
            contact.isValid() -> userData.fillInWithUserContact(contact)
            else -> userData
        }
    }
compiler is complaining
contact
inside
invoke
fillWithUserContact
is nullable. shouldn’t
contract
ensure it’s not treated as nullable?
h
you must use
contact.isValid() == true
. if
contact
is null,
isValid
is not called, and returns
null
.
j
@hfhbd the
isValid()
extension is defined on the nullable type, so I don't think what you wrote is correct
4
h
But when requires a
Boolean
not a
Boolean?
. So you need to call
== true
anyway, and the smart cast works as expected.
Copy code
@ExperimentalContracts
fun main() {
    val a: String? = ""
    val length = when {
        a.a() -> a.length
        else -> -1
    }
    println(length)
}

@ExperimentalContracts
fun String?.a(): Boolean? {
    contract {
        returns(null) implies (this@a == null)
        returns(true) implies (this@a != null)
    }
    return this != null
}
k
@hfhbd the expression
contact.isValid()
returns a
Boolean
, not a
Boolean?
. In the same way as
null.toString()
returns a
String
(with the value "null") and not a
String?
So when
contact
is null ,
contact.isValid()
returns
false
. It never returns null.
4
🤦‍♂️ 2
h
Oh, you are right. I did add a useless
?
...
Copy code
fun main() {
    val a: String? = ""
    val length = when {
        a.a() -> a.length
        else -> -1
    }
    println(length)
}

@ExperimentalContracts
fun String?.a(): Boolean {
    contract {
        returns(true) implies (this@a != null)
    }
    return this != null
}
But why does it work for this sample? 🤔
j
Maybe an inference/contract bug? The calling function in the OP is a
suspend
fun, so that might break inference somewhere