Kotlin and how to convert an if/else to functional approach?

693 Views Asked by At

I have a function in this format:

fun myFunction(param1: Int, param2: String, param3: Number): Number =
    if(param1 < NUMBER) {
        if(param2 == "FOO") {
            // code for result
        } else {
            // code for result
        }
    } else {

        if (param2 == "FOO") {
            //code for result
        } else {
            // code for result
        }
    }

How could I change it so that it has a more functional approach? I suspect that I should be able to use some function value since I do the same if check in both if/else branches

1

There are 1 best solutions below

0
gidds On

Hmmm.  It's already functional, really: each if is returning a value; there are no side-effects (nor even any assignments); and the whole function is defined as an expression.  There's nothing imperative: it says what should be done, not how.

This demonstrates that a functional style doesn't always guarantee short code :-)

Of course, it's still a bit long-winded, but I can't see any obvious ways to improve it.

One alternative would be a when, but you'd still have to repeat at least one of the tests.  For example:

fun myFunction(param1: Int, param2: String, param3: Number): Number = when {
    param1 < NUMBER && param2 == "FOO" -> // code for result
    param1 < NUMBER -> // code for result
    param2 == "FOO" -> // code for result
    else -> // code for result
}

That's the ‘minimal’ version.  It's shorter; but by avoiding unnecessary repetition you lose the symmetry, making it harder to follow the tests.  (You also add a dependency on the order of the tests, which the version in the question doesn't have.)

Alternatively, repeating the tests is probably clearer to read, and is order-independent; but more prone to error if someone changes one test without adjusting all the others — and you also need an else to please the compiler, which can't tell that the four cases are exhaustive:

fun myFunction(param1: Int, param2: String, param3: Number): Number = when {
    param1 <  NUMBER && param2 == "FOO" -> // code for result
    param1 <  NUMBER && param2 != "FOO" -> // code for result
    param1 >= NUMBER && param2 == "FOO" -> // code for result
    param1 >= NUMBER && param2 != "FOO" -> // code for result
    else -> throw RuntimeException("Shouldn't happen")
}

Depending what this is doing, there might be more sophisticated approaches — e.g. a list of matcher objects or whatever.  But those won't be any shorter, either.

So the only change I might make, if the results were short expressions, would just be to drop unnecessary line-breaks and braces:

fun myFunction(p1: Int, p2: String, p3: Number) =
    if (p1 < NUMBER) {
        if (p2 == "FOO") 1 else 2
    } else {
        if (p2 == "FOO") 3 else 4
    }