Hello every one, would appreciate it if you can gi...
# android
a
Hello every one, would appreciate it if you can give me your opinion on the following matter. I want to decide which one of the following block of codes is better to use and why? 1st Block:
Copy code
nullableVarParent?.let { nonNullParent ->

    if (
    		nonNullParent.nullableValChildOne == null
         || nonNullParent.nullableValChildTwo == null 
    ) 
      return
    
    funcEx(
         nonNullParent.nullableValChildOne,   
         nonNullParent.nullableValChildTwo
    )
}
2nd Block
Copy code
if (
    		nullableVarParent?.nullableValChildOne == null
         || nullableVarParent?.nullableValChildTwo == null 
    ) 
      return
    
funcEx(
     nullableVarParent?.nullableValChildOne!!,   
     nullableVarParent?.nullableValChildTwo!!
)
Some would think the second one is safe too because of the if condition, but is it better to use? Appreciate your support.
l
What about a 3rd approach:
Copy code
fun <T : Any, R : Any> whenAnyNotNull(vararg options: T?, block: (List<T>) -> R) {
    if (options.any { it != null }) {
        block(options.filterNotNull())
    }
}
use it like:
Copy code
whenAnyNotNull(nullableVarParent?.nullableValChildOne, nonNullParent.nullableValChildTwo) { (a, b) ->
    funcEx(a, b)
} ?: return
1
but your condition does not make any sense so I guess you are looking for:
Copy code
fun <T : Any, R: Any> whenAllNotNull(vararg options: T?, block: (List<T>) -> R): R? {
    if (options.all { it != null }) {
        return block(options.filterNotNull()) // or do unsafe cast to non null collection
    }
    return null
}
Copy code
whenAllNotNull(nullableVarParent?.nullableValChildOne, nonNullParent.nullableValChildTwo) { (a, b) ->
    funcEx(a, b)
} ?: return
1
a
If the parent object is mutable, neither of those is safe; the child values might change between the test and the usage. You could use let (or a similar extension function)
Copy code
nullableVarParent?.nullableValChildOne?.let { nonNullChildOne ->
   nullableVarParent?.nullableValChildTwo?.let { nonNullChildTwo ->
      funcEx(nonNullChildOne, nonNullChildTwo
   }
}
though it’s not very readable. Honestly it might be simplest to just say
Copy code
funcEx(
   nullableVarParent?.nullableValChildOne ?: return,
   nullableVarParent?.nullableValChildTwo ?: return
)
1
a
@Lilly @Aidan Low The point is that I had a friendly discussion with a college about how unsafe the second code is, to use !! operator after if check. He is totally convinced that the mutable parent is impossible to be null after the if condition since we don't use threads in this area. It some how believable but since everyone in the world has been saying to avoid suppression (!!) in all cases, I wanted to make sure. can two functions be executed concurrently on the same thread and change the value of same variable?
l
I have no experience with concurrency and mutating state. I guess it's never a good idea...hard to track, hard to debug
👍 1
a
Well, you can’t execute multiple functions concurrently on the same thread, that’s one definition of a thread, but let’s leave that aside. If your code is single-threaded and you can guarantee that no one is going to modify the contents of the parent object, both blocks of code are technically safe. However, they’re both extremely fragile; if someone comes along and makes this multi-threaded later without realizing that you’ve done this, you have a crash waiting to happen. Same if someone reorders this code or adds in additional code that modifies the parent between the check and the !!. Kotlin includes a mechanisms to help you avoid this kind of fragility, whether the scope functions (my first example with let) or the ?: operator (my second example with early returns inside a function invocation), and I’d recommend you get into the habit of using these.