1

I have a method as follows:

fun <T1, T2, T3> ifCoordsNotNull(v1: T1?, v2: T2?, v3: T3?, allNotNull: (T1, T2, T3) -> (Unit)) {
    if (v1 != null && v2 != null && v3 != null) {
        allNotNull(v1, v2, v3)
    }
}

I know this is a way to check if multiple values are null; however, it seems to be not too efficient for my needs unless I make several related methods.

Is there a way I could put any/all variables I need to check for null into a list/set, and then recover the results (if any) in a callback with a single method?

To be more specific, I can use the current method like this:

ifCoordsNotNull(loc["x"], loc["y"], loc["z"]) { x, y, z ->

But would prefer, if possible, to create a more ergonomic method that can work in many situations like this:

ifNotNull(linkedSetOf(loc["x"], loc["y"], loc["z"])) { x, y, z ->

If there's anything similar, or a better practice for my needs, please do let me know. Thank you.

Kaxon
  • 25
  • 3

3 Answers3

-1

You can make use of vararg keyword and filterNotNull, for example:

fun ifNotNull(vararg input: Any?, function: (s: List<Any>) -> Unit) {
    val list = input.filterNotNull().toList()

    if (list.size != input.size) {
        throw RuntimeException()
    }

    function(list)
}

Results would be:

ifNotNull(1, 2, 3) {
    println(it)
} // [1, 2, 3]

ifNotNull("a", 1, null) {
    println(it)
} // Throws
Alexey Soshin
  • 16,718
  • 2
  • 31
  • 40
  • The problem is that once `function` argument needs to access the input with the correct type, you need to write something like `ifNotNull(1, 2, 3) { list -> val x = list[0] as Int; ... }`. Yuck. It can be at least improved for the case where all arguments are the same type. – Alexey Romanov Dec 02 '18 at 12:59
  • Yep. But since example uses three different types, I decided to forgo generics here. – Alexey Soshin Dec 02 '18 at 13:20
-1

What you'd need to do it properly is generics with variable number of type parameters, which Kotlin doesn't have. Actually the only language I know of which does have something like this is C++.

Otherwise you'll either:

  1. lose types and/or number of parameters as in Alexey Soshin's answer

  2. have to introduce classes for different numbers of parameters which ends up as more work than declaring a method for each number of parameters.

Alexey Romanov
  • 167,066
  • 35
  • 309
  • 487
-1

Some variant on the following perhaps:

fun check(vars: Array<Any?>): Boolean = vars.filterNotNull().size == vars.size


fun <T1, T2, T3> ifCoordsNotNull(v1: T1?, v2: T2?, v3: T3?, allNotNull: (T1, T2, T3) -> (Unit)) {
    if (check(arrayOf(v1, v2, v3))) {
        allNotNull(v1!!, v2!!, v3!!)
    }
}

You may be able to get rid of !! using Contracts (https://kotlinlang.org/docs/reference/whatsnew13.html#contracts)

David Soroko
  • 8,521
  • 2
  • 39
  • 51