Search code examples
kotlinkotlin-null-safety

Null safety error showing after checking for null


I perform a function (listOf(matchUid, first_name, gender, matchBio, age).any { it == null }) that checks if any of the variables passed in are null:

private fun getMatchData(doc: DocumentSnapshot){
    val matchUid = if (isUser1) doc.getString("user2") else doc.getString("user1")
    val first_name = if (isUser1) doc.getString("user2name") else doc.getString("user1name")
    val gender = if (isUser1) doc.getString("user2gender") else doc.getString("gender")
    val matchBio = if (isUser1) doc.getString("user2bio") else doc.getString("user1bio")
    if ( listOf(matchUid, first_name, gender, matchBio, age).any { it == null } ) return goOffline()
    if (matchUid == null) return goOffline()
    if (!isUser1) Group = Group().apply {
        id = doc.id
        user1 = matchUid
        user2 = user.uid
        match = User(matchUid, first_name, gender, null, true)
    } 

Even though it checks this, first_name and gender have red underlines from the compiler due to null safety. matchUid doesn't have a red line because I explicitly check for null on it the line below.

Why is the compiler still giving a null warning after I already check it?


Solution

  • So, the problem is that compiler is not smart enough, or... we do not provide enough information.

    In your case the problematic call where you ensure that firstName and gender is not null is:

    if (listOf(matchUid, firstName, gender, matchBio, age).any { it == null }) return goOffline()
    

    If you change it to simple chain of nulls it would working properly:

    if (matchUid == null || firstName == null || gender == null || matchBio == null || age == null) return goOffline()
    

    So, why is that? Compiler just don't know that listOf(vararg objects: Any?).any { it == null } means, that none of that objects are not null. So, what we can do?

    Kotlin 1.3 gave us a great possibility to write contracts, which are a tip for compilator that, for example, if f(x) returns true means x is not null. But, unfortunately, contracts doesn't support varargs argument (or I haven't found a way to do that).

    So, in your case you can replace your call with chain of single null checking.