Using Kotlin WHEN clause for <, <=, >=, > comparisons

Viewed 32094

I'm trying to use the WHEN clause with a > or < comparison.

This doesn't compile. Is there a way of using the normal set of boolean operators (< <=, >= >) in a comparison to enable this?

val foo = 2

// doesn't compile
when (foo) {
    > 0 -> doSomethingWhenPositive()
    0   -> doSomethingWhenZero()
    < 0 -> doSomethingWhenNegative()
}

I tried to find an unbounded range comparison, but couldn't make this work either? Is it possible to write this as an unbounded range?

// trying to get an unbounded range - doesn't compile
when (foo) {
    in 1.. -> doSomethingWhenPositive()
    else -> doSomethingElse()
}

You can put the whole expression in the second part, which is OK but seems like unnecessary duplication. At least it compiles and works.

when {
    foo > 0 -> doSomethingWhenPositive()
    foo < 0 -> doSomethingWhenNegative()
    else -> doSomethingWhenZero()
}

But I'm not sure that is any simpler than the if-else alternative we have been doing for years. Something like:

if ( foo > 0 ) {
    doSomethingWhenPositive()
}
else if (foo < 0) {
    doSomethingWhenNegative()
}
else {
    doSomethingWhenZero()
}

Of course, real world problems are more complex than the above, and the WHEN clause is attractive but doesn't work as I expect for this type of comparison.

6 Answers

We can use let to achieve this behaviour.

response.code().let {
    when {
        it == 200 -> handleSuccess()
        it == 401 -> handleUnauthorisedError()
        it >= 500 -> handleInternalServerError()
        else -> handleOtherErrors()
    }
}

Hope this helps

I found a bit hacky way that can help you in mixing greater than, less than, or any other expression with other in expressions. Simply, a when statement in Kotlin looks at the "case", and if it is a range, it sees if the variable is in that range, but if it isn't, it looks to see if the case is of the same type of the variable, and if it isn't, you get a syntax error. So, to get around this, you could do something like this:

when (foo) {
    if(foo > 0) foo else 5 /*or any other out-of-range value*/ -> doSomethingWhenPositive()
    in -10000..0   -> doSomethingWhenBetweenNegativeTenKAndZero()
    if(foo < -10000) foo else -11000 -> doSomethingWhenNegative()
}

As you can see, this takes advantage of the fact that everything in Kotlin is an expression. So, IMO, this is a pretty good solution for now until this feature gets added to the language.

I use this:

val foo = 2

when (min(1, max(-1, foo))) {
    +1 -> doSomethingWhenPositive()
     0 -> doSomethingWhenZero()
    -1 -> doSomethingWhenNegative()
}

The imports needed for this case are:

import java.lang.Integer.min
import java.lang.Integer.max

but they can be generalized to other types.

You're welcome!

Related