Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How can I check if a set of functions all return non null, in a single expression?

Suppose I have three functions foo, bar, baz, all of which return nullable types.

fun foo(): Int? = 1
fun bar(): Int? = 2
fun baz(): Int? = 3

I want to call them, and if all them returns non-null, I want to compute a value from their return values.

I could do this with statements, like this:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

val x = foo()
val y = bar()
val z = baz()
val result = if (x != null && y != null && z != null) x + y + z else null

However, I don’t like the fact that I have to declare 3 extra variables that I can still access afterwards. By having 3 extra statements like this, it also means that I cannot use expression-bodied functions, if I were writing a function that returns result.

If I use lets instead:

val result = foo()?.let { x -> 
    bar()?.let { y -> 
        baz()?.let { z -> 
            x + y + z
        } 
    } 
}

This creates a deep nesting. If it were only one function, this would have been fine, but with 3 functions or more, this makes my intention of "call these three functions, if they are all non null, add them together" rather unclear.

How can I write this in a way that clearly conveys my intention, but also making it a single expression?

>Solution :

If they are of different types, I think you need to write your own helper functions like these (different overloads needed for different numbers of parameters, because there’s no other way for the compiler to know the types of the arguments):

inline fun <T : Any, U : Any, R> ifAllNotNull(t: T?, u: U?, block: (t: T, u: U) -> R): R? {
    return when {
        t != null && u != null -> block(t, u)
        else -> null
    }
}

inline fun <T : Any, U : Any, V : Any, R> ifAllNotNull(t: T?, u: U?, v: V?, block: (t: T, u: U, v: V) -> R): R? {
    return when {
        t != null && u != null && v != null -> block(t, u, v)
        else -> null
    }
}
val result = ifAllNotNull(foo(), bar(), baz()) { x, y, z -> x + y + z }

Note that all three parameters will be evaluated before any are checked for null.


Or if you want to do what you described (hiding the three variables after the result calculation) using just standard library functions, you can use run to limit the scope of the temporary variables:

val result = run {
    val x = foo()
    val y = bar()
    val z = baz()
    if (x != null && y != null && z != null) x + y + z else null
}

This would also give you the opportunity to short-circuit if you like:

val result = run {
    val x = foo() ?: return@run null
    val y = bar() ?: return@run null
    val z = baz() ?: return@run null
    x + y + z
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading